diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/third_party/libgcrypt/random | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/third_party/libgcrypt/random')
20 files changed, 10950 insertions, 0 deletions
diff --git a/comm/third_party/libgcrypt/random/ChangeLog-2011 b/comm/third_party/libgcrypt/random/ChangeLog-2011 new file mode 100644 index 0000000000..cd45c3d666 --- /dev/null +++ b/comm/third_party/libgcrypt/random/ChangeLog-2011 @@ -0,0 +1,191 @@ +2011-12-01 Werner Koch <wk@g10code.com> + + NB: ChangeLog files are no longer manually maintained. Starting + on December 1st, 2011 we put change information only in the GIT + commit log, and generate a top-level ChangeLog file from logs at + "make dist". See doc/HACKING for details. + +2011-09-08 Werner Koch <wk@g10code.com> + + * rndlinux.c (_gcry_rndlinux_gather_random): Don't use select if + the fd number is too high. Reported by Jakub Bogusz. + +2010-10-18 Werner Koch <wk@g10code.com> + + * rndw32.c (registry_poll): Disable performace fata gathering if + GNUPG_RNDW32_NOPERF has been set. + +2010-04-27 Marcus Brinkmann <marcus@g10code.de> + + * rndw32ce.c (fillup_buffer): Rewrite without using nested + functions, which are broken on arm/cegcc. + +2010-04-12 Brad Hards <bradh@frogmouth.net> (wk) + + Spelling fixes. + +2010-03-24 Werner Koch <wk@g10code.com> + + * rndw32.c: Revert all changes from 2010-01-21. + + * rndw32ce.c: New. + * Makefile.am (EXTRA_librandom_la_SOURCES): Add it. + * random-csprng.c (getfnc_gather_random) + (getfnc_fast_random_poll) [USE_RNDW32CE]: Use rndw32ce. + +2010-01-21 Werner Koch <wk@g10code.com> + + * rndw32.c (read_mbm_data) [W32CE]: Do not build. + (slow_gatherer) [W32CE]: Do not call read_mbm_data. + (_gcry_rndw32_gather_random_fast) [W32CE]: Exclude some calls. + (_gcry_rndw32_gather_random): Adjust version test for WindowsCE. + +2009-12-10 Werner Koch <wk@g10code.com> + + * rndw32.c (system_is_w2000): New. + (_gcry_rndw32_gather_random): Set it. + (slow_gatherer): Ignore SystemObjectInformation on W2000. Fixes + bug#1167. + +2009-07-09 Werner Koch <wk@g10code.com> + + * rndlinux.c (_gcry_rndlinux_gather_random): Print real values for + the progess function and call it before blocking. Suggested by + Christian Grothoff. + * rndunix.c (slow_poll): Add similar, but not yet functional, code. + +2009-07-02 Werner Koch <wk@g10code.com> + + * rndhw.c (poll_padlock): Asm change from Fedora. + +2009-01-22 Werner Koch <wk@g10code.com> + + * random.c (_gcry_random_deinit_external_test): Do not return a + value. Reported Albert Chin. + +2008-09-16 Werner Koch <wk@g10code.com> + + * random-fips.c (x931_aes_driver): No re-seeding with test contexts. + (_gcry_rngfips_init_external_test): Fix setting of test_dt_ptr. + (struct rng_context): Add flag TEST_NO_DUP_CHECK. + (x931_aes_driver): Use that flag. + (_gcry_rngfips_init_external_test): Add arg FLAGS and use it to + modify the test. + * random.c (_gcry_random_init_external_test): Pass FLAGS. + +2008-09-15 Werner Koch <wk@g10code.com> + + * random.c (_gcry_random_init_external_test): New. + (_gcry_random_run_external_test): New. + (_gcry_random_deinit_external_test): New. + * random-fips.c (struct rng_context): Turn TEST_DT_COUNTER into a + 32 bit integer. + (x931_get_dt): Ditto. + (selftest_kat): Intialize it accordingly. + (_gcry_rngfips_init_external_test): New. + (_gcry_rngfips_run_external_test): New. + (_gcry_rngfips_deinit_external_test): New. + +2008-09-05 Werner Koch <wk@g10code.com> + + * random.c (_gcry_random_selftest): Return success if not in fips + mode. + +2008-09-01 Werner Koch <wk@g10code.com> + + * random-fips.c (x931_get_dt) [W32]: Do not use getppid. + (get_entropy): Prepare for use under Windows. + (_gcry_rngfips_selftest): Ditto. + (entropy_collect_cb): Make sure that the gatherer never overflows + the buffers. + +2008-08-29 Werner Koch <wk@g10code.com> + + * random-fips.c (SEED_TTL): New. + (struct rng_context): Add USE_COUNTER, remove NEED_STRONG_ENTROPY. + (x931_aes_driver): Do re-seeding if required. + (x931_generate_key, x931_generate_seed): Factor common code out to .. + (get_entropy): .. new. Always use /dev/random. + (x931_generate_key): Seed key for nonce_context from std_rng_context. + (x931_reseed): New. Seed nonce context from std_rng_context. + (get_random): Use x931_reseed. + (_gcry_rngfips_selftest): Return an error if no /dev/radom support + has been compiled in. + (get_random): Remove locking. + (_gcry_rngfips_randomize, _gcry_rngfips_create_nonce): Lock here. + +2008-08-28 Werner Koch <wk@g10code.com> + + * random-daemon.c (connect_to_socket): Use GPG_ERR_ENAMETOOLONG. + +2008-08-25 Werner Koch <wk@g10code.com> + + * random-fips.c (x931_aes): Take datetime_GT from an arg. + (x931_aes_driver): Call x931_get_dt here. + (x931_get_dt): Implement the KAT hack. + (x931_generate_seed): Copy the seed value to the provided buffer. + (selftest_kat): New. + +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. + +2008-08-15 Werner Koch <wk@g10code.com> + + * random-fips.c: New. + + * random-csprng.c (process-cb, progress_cb_data): Move to + random.c. + (_gcry_register_random_progress, _gcry_random_progress): Ditto. + (_gcry_random_initialize): Rename to _gcry_rngcsprng_initialize. + (_gcry_random_dump_stats): Rename to _gcry_rngcsprng_dump_stats. + (_gcry_secure_random_alloc): Rename to + _gcry_rngcsprng_secure_alloc. + (_gcry_enable_quick_random_gen): Rename to + _gcry_rngcsprng_enable_quick_gen. + (_gcry_set_random_daemon_socket): Rename to + _gcry_rngcsprng_set_daemon_socket. + (_gcry_use_random_daemon): Rename to _gcry_rngcsprng_use_daemon. + (_gcry_random_is_faked): Rename to _gcry_rngcsprng_is_faked. + (gcry_random_add_bytes): Rename to _gcry_rngcsprng_add_bytes. + (gcry_random_bytes): Remove + (gcry_random_bytes_secure): Remove. + (gcry_randomize): Rename to _gcry_rngcsprng_randomize. + (_gcry_set_random_seed_file): Rename to + _gcry_rngcsprng_set_seed_file. + (_gcry_update_random_seed_file): Rename to + _gcry_rngcsprng_update_seed_file. + (_gcry_fast_random_poll): Rename to _gcry_rngcsprng_fast_poll. + (gcry_create_nonce): Rename to _gcry_rngcsprng_create_nonce. + + * random.c: Factor all code out to random-csprng.c and implement + wrapper functions. + +2008-07-05 Werner Koch <wk@g10code.com> + + * random-daemon.c, random.h, rndhw.c, rndunix.c, rand-internal.h * + random.c, rndegd.c, rndlinux.c, rndw32.c: Move from ../cipher/ to + here. + * Makefile.am: New. + + Copyright 2008, 2009 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +Local Variables: +buffer-read-only: t +End: diff --git a/comm/third_party/libgcrypt/random/Makefile.am b/comm/third_party/libgcrypt/random/Makefile.am new file mode 100644 index 0000000000..7e6e6f032f --- /dev/null +++ b/comm/third_party/libgcrypt/random/Makefile.am @@ -0,0 +1,69 @@ +# Makefile for cipher modules +# Copyright (C) 2008 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt 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. +# +# Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + +# Process this file with automake to produce Makefile.in + +# Need to include ../src in addition to top_srcdir because gcrypt.h is +# a built header. +AM_CPPFLAGS = -I../src -I$(top_srcdir)/src +AM_CFLAGS = $(GPG_ERROR_CFLAGS) + +noinst_LTLIBRARIES = librandom.la + +GCRYPT_MODULES = @GCRYPT_RANDOM@ + +librandom_la_DEPENDENCIES = $(GCRYPT_MODULES) +librandom_la_LIBADD = $(GCRYPT_MODULES) + +librandom_la_SOURCES = \ +random.c random.h \ +rand-internal.h \ +random-csprng.c \ +random-drbg.c \ +random-system.c \ +rndjent.c \ +rndhw.c + +if USE_RANDOM_DAEMON +librandom_la_SOURCES += random-daemon.c +endif USE_RANDOM_DAEMON + + +EXTRA_librandom_la_SOURCES = \ +rndlinux.c \ +rndegd.c \ +rndunix.c \ +rndw32.c \ +rndw32ce.c \ +jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h + + +# The rndjent module needs to be compiled without optimization. */ +if ENABLE_O_FLAG_MUNGING +o_flag_munging = sed -e 's/-O\([1-9sg][1-9sg]*\)/-O0/g' -e 's/-Ofast/-O0/g' +else +o_flag_munging = cat +endif + +rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + +rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` diff --git a/comm/third_party/libgcrypt/random/Makefile.in b/comm/third_party/libgcrypt/random/Makefile.in new file mode 100644 index 0000000000..f9489de14b --- /dev/null +++ b/comm/third_party/libgcrypt/random/Makefile.in @@ -0,0 +1,744 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile for cipher modules +# Copyright (C) 2008 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt 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. +# +# Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + +# Process this file with automake to produce Makefile.in + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@USE_RANDOM_DAEMON_TRUE@am__append_1 = random-daemon.c +subdir = random +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cc_for_build.m4 \ + $(top_srcdir)/m4/gpg-error.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/noexecstack.m4 $(top_srcdir)/m4/socklen.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +am__librandom_la_SOURCES_DIST = random.c random.h rand-internal.h \ + random-csprng.c random-drbg.c random-system.c rndjent.c \ + rndhw.c random-daemon.c +@USE_RANDOM_DAEMON_TRUE@am__objects_1 = random-daemon.lo +am_librandom_la_OBJECTS = random.lo random-csprng.lo random-drbg.lo \ + random-system.lo rndjent.lo rndhw.lo $(am__objects_1) +librandom_la_OBJECTS = $(am_librandom_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/jitterentropy-base.Plo \ + ./$(DEPDIR)/random-csprng.Plo ./$(DEPDIR)/random-daemon.Plo \ + ./$(DEPDIR)/random-drbg.Plo ./$(DEPDIR)/random-system.Plo \ + ./$(DEPDIR)/random.Plo ./$(DEPDIR)/rndegd.Plo \ + ./$(DEPDIR)/rndhw.Plo ./$(DEPDIR)/rndjent.Plo \ + ./$(DEPDIR)/rndlinux.Plo ./$(DEPDIR)/rndunix.Plo \ + ./$(DEPDIR)/rndw32.Plo ./$(DEPDIR)/rndw32ce.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(librandom_la_SOURCES) $(EXTRA_librandom_la_SOURCES) +DIST_SOURCES = $(am__librandom_la_SOURCES_DIST) \ + $(EXTRA_librandom_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +BUILD_VERSION = @BUILD_VERSION@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DL_LIBS = @DL_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@ +FALLBACK_SOCKLEN_T = @FALLBACK_SOCKLEN_T@ +FGREP = @FGREP@ +GCRYPT_CIPHERS = @GCRYPT_CIPHERS@ +GCRYPT_DIGESTS = @GCRYPT_DIGESTS@ +GCRYPT_HWF_MODULES = @GCRYPT_HWF_MODULES@ +GCRYPT_KDFS = @GCRYPT_KDFS@ +GCRYPT_PUBKEY_CIPHERS = @GCRYPT_PUBKEY_CIPHERS@ +GCRYPT_RANDOM = @GCRYPT_RANDOM@ +GPGRT_CONFIG = @GPGRT_CONFIG@ +GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GPG_ERROR_LIBS = @GPG_ERROR_LIBS@ +GPG_ERROR_MT_CFLAGS = @GPG_ERROR_MT_CFLAGS@ +GPG_ERROR_MT_LIBS = @GPG_ERROR_MT_LIBS@ +GREP = @GREP@ +INSERT_SYS_SELECT_H = @INSERT_SYS_SELECT_H@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDADD_FOR_TESTS_KLUDGE = @LDADD_FOR_TESTS_KLUDGE@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CIPHERS = @LIBGCRYPT_CIPHERS@ +LIBGCRYPT_CONFIG_API_VERSION = @LIBGCRYPT_CONFIG_API_VERSION@ +LIBGCRYPT_CONFIG_CFLAGS = @LIBGCRYPT_CONFIG_CFLAGS@ +LIBGCRYPT_CONFIG_HOST = @LIBGCRYPT_CONFIG_HOST@ +LIBGCRYPT_CONFIG_LIBS = @LIBGCRYPT_CONFIG_LIBS@ +LIBGCRYPT_DIGESTS = @LIBGCRYPT_DIGESTS@ +LIBGCRYPT_LT_AGE = @LIBGCRYPT_LT_AGE@ +LIBGCRYPT_LT_CURRENT = @LIBGCRYPT_LT_CURRENT@ +LIBGCRYPT_LT_REVISION = @LIBGCRYPT_LT_REVISION@ +LIBGCRYPT_PUBKEY_CIPHERS = @LIBGCRYPT_PUBKEY_CIPHERS@ +LIBGCRYPT_THREAD_MODULES = @LIBGCRYPT_THREAD_MODULES@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MPI_SFLAGS = @MPI_SFLAGS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NOEXECSTACK_FLAGS = @NOEXECSTACK_FLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTH_CFLAGS = @PTH_CFLAGS@ +PTH_CONFIG = @PTH_CONFIG@ +PTH_LIBS = @PTH_LIBS@ +RANLIB = @RANLIB@ +RC = @RC@ +RUN_LARGE_DATA_TESTS = @RUN_LARGE_DATA_TESTS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYSROOT = @SYSROOT@ +VERSION = @VERSION@ +VERSION_NUMBER = @VERSION_NUMBER@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +emacs_local_vars_begin = @emacs_local_vars_begin@ +emacs_local_vars_end = @emacs_local_vars_end@ +emacs_local_vars_read_only = @emacs_local_vars_read_only@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Need to include ../src in addition to top_srcdir because gcrypt.h is +# a built header. +AM_CPPFLAGS = -I../src -I$(top_srcdir)/src +AM_CFLAGS = $(GPG_ERROR_CFLAGS) +noinst_LTLIBRARIES = librandom.la +GCRYPT_MODULES = @GCRYPT_RANDOM@ +librandom_la_DEPENDENCIES = $(GCRYPT_MODULES) +librandom_la_LIBADD = $(GCRYPT_MODULES) +librandom_la_SOURCES = random.c random.h rand-internal.h \ + random-csprng.c random-drbg.c random-system.c rndjent.c \ + rndhw.c $(am__append_1) +EXTRA_librandom_la_SOURCES = \ +rndlinux.c \ +rndegd.c \ +rndunix.c \ +rndw32.c \ +rndw32ce.c \ +jitterentropy-base.c jitterentropy.h jitterentropy-base-user.h + +@ENABLE_O_FLAG_MUNGING_FALSE@o_flag_munging = cat + +# The rndjent module needs to be compiled without optimization. */ +@ENABLE_O_FLAG_MUNGING_TRUE@o_flag_munging = sed -e 's/-O\([1-9sg][1-9sg]*\)/-O0/g' -e 's/-Ofast/-O0/g' +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu random/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu random/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +librandom.la: $(librandom_la_OBJECTS) $(librandom_la_DEPENDENCIES) $(EXTRA_librandom_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(librandom_la_OBJECTS) $(librandom_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jitterentropy-base.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-csprng.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-daemon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-drbg.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-system.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndegd.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndhw.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndjent.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndlinux.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndunix.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndw32.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndw32ce.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/jitterentropy-base.Plo + -rm -f ./$(DEPDIR)/random-csprng.Plo + -rm -f ./$(DEPDIR)/random-daemon.Plo + -rm -f ./$(DEPDIR)/random-drbg.Plo + -rm -f ./$(DEPDIR)/random-system.Plo + -rm -f ./$(DEPDIR)/random.Plo + -rm -f ./$(DEPDIR)/rndegd.Plo + -rm -f ./$(DEPDIR)/rndhw.Plo + -rm -f ./$(DEPDIR)/rndjent.Plo + -rm -f ./$(DEPDIR)/rndlinux.Plo + -rm -f ./$(DEPDIR)/rndunix.Plo + -rm -f ./$(DEPDIR)/rndw32.Plo + -rm -f ./$(DEPDIR)/rndw32ce.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/jitterentropy-base.Plo + -rm -f ./$(DEPDIR)/random-csprng.Plo + -rm -f ./$(DEPDIR)/random-daemon.Plo + -rm -f ./$(DEPDIR)/random-drbg.Plo + -rm -f ./$(DEPDIR)/random-system.Plo + -rm -f ./$(DEPDIR)/random.Plo + -rm -f ./$(DEPDIR)/rndegd.Plo + -rm -f ./$(DEPDIR)/rndhw.Plo + -rm -f ./$(DEPDIR)/rndjent.Plo + -rm -f ./$(DEPDIR)/rndlinux.Plo + -rm -f ./$(DEPDIR)/rndunix.Plo + -rm -f ./$(DEPDIR)/rndw32.Plo + -rm -f ./$(DEPDIR)/rndw32ce.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +rndjent.o: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(COMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + +rndjent.lo: $(srcdir)/rndjent.c jitterentropy-base-user.h \ + $(srcdir)/jitterentropy-base.c $(srcdir)/jitterentropy.h + `echo $(LTCOMPILE) -c $(srcdir)/rndjent.c | $(o_flag_munging) ` + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/comm/third_party/libgcrypt/random/jitterentropy-base-user.h b/comm/third_party/libgcrypt/random/jitterentropy-base-user.h new file mode 100644 index 0000000000..8a8dbd5581 --- /dev/null +++ b/comm/third_party/libgcrypt/random/jitterentropy-base-user.h @@ -0,0 +1,134 @@ +/* + * Non-physical true random number generator based on timing jitter. + * + * Copyright Stephan Mueller <smueller@chronox.de>, 2013 + * + * License + * ======= + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef GCRYPT_JITTERENTROPY_BASE_USER_H +#define GCRYPT_JITTERENTROPY_BASE_USER_H + +/* + * This is Libgcrypt specific platform dependent code. We use a + * separate file because jitterentropy.h expects such a file. + */ + +#ifndef USE_JENT +# error This file expects to be included from rndjent.c (via jitterentropy.h) +#endif +#ifndef HAVE_STDINT_H +# error This module needs stdint.h - try ./configure --disable-jent-support +#endif + + +/* When using the libgcrypt secure memory mechanism, all precautions + * are taken to protect our state. If the user disables secmem during + * runtime, it is his decision and we thus try not to overrule his + * decision for less memory protection. */ +#define JENT_CPU_JITTERENTROPY_SECURE_MEMORY 1 +#define jent_zalloc(n) _gcry_calloc_secure (1, (n)) + + +static void +jent_get_nstime(u64 *out) +{ +#if USE_JENT == JENT_USES_RDTSC + + u32 t_eax, t_edx; + + asm volatile (".byte 0x0f,0x31\n\t" + : "=a" (t_eax), "=d" (t_edx) + ); + *out = (((u64)t_edx << 32) | t_eax); + +#elif USE_JENT == JENT_USES_GETTIME + + struct timespec tv; + u64 tmp; + + /* On Linux we could use CLOCK_MONOTONIC(_RAW), but with + * CLOCK_REALTIME we get some nice extra entropy once in a while + * from the NTP actions that we want to use as well... though, we do + * not rely on that extra little entropy. */ + if (!clock_gettime (CLOCK_REALTIME, &tv)) + { + tmp = tv.tv_sec; + tmp = tmp << 32; + tmp = tmp | tv.tv_nsec; + } + else + tmp = 0; + *out = tmp; + +#elif USE_JENT == JENT_USES_READ_REAL_TIME + + /* clock_gettime() on AIX returns a timer value that increments in + * steps of 1000. */ + u64 tmp = 0; + + timebasestruct_t aixtime; + read_real_time (&aixtime, TIMEBASE_SZ); + tmp = aixtime.tb_high; + tmp = tmp << 32; + tmp = tmp | aixtime.tb_low; + *out = tmp; + +#else +# error No clock available in jent_get_nstime +#endif +} + + +static GPGRT_INLINE void +jent_zfree (void *ptr, unsigned int len) +{ + if (ptr) + { + wipememory (ptr, len); + _gcry_free (ptr); + } +} + + +static GPGRT_INLINE int +jent_fips_enabled(void) +{ + return fips_mode(); +} + + +#endif /* GCRYPT_JITTERENTROPY_BASE_USER_H */ diff --git a/comm/third_party/libgcrypt/random/jitterentropy-base.c b/comm/third_party/libgcrypt/random/jitterentropy-base.c new file mode 100644 index 0000000000..ba435e1bdb --- /dev/null +++ b/comm/third_party/libgcrypt/random/jitterentropy-base.c @@ -0,0 +1,791 @@ +/* + * Non-physical true random number generator based on timing jitter. + * + * Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2017 + * + * Design + * ====== + * + * See documentation in doc/ folder. + * + * Interface + * ========= + * + * See documentation in doc/ folder. + * + * License + * ======= + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL2 are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#undef _FORTIFY_SOURCE +#pragma GCC optimize ("O0") + +#include "jitterentropy.h" + +#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT + /* only check optimization in a compilation for real work */ + #ifdef __OPTIMIZE__ + #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy-base.c." + #endif +#endif + +#define MAJVERSION 2 /* API / ABI incompatible changes, functional changes that + * require consumer to be updated (as long as this number + * is zero, the API is not considered stable and can + * change without a bump of the major version) */ +#define MINVERSION 1 /* API compatible, ABI may change, functional + * enhancements only, consumer can be left unchanged if + * enhancements are not considered */ +#define PATCHLEVEL 0 /* API / ABI compatible, no functional changes, no + * enhancements, bug fixes only */ + +/** + * jent_version() - Return machine-usable version number of jent library + * + * The function returns a version number that is monotonic increasing + * for newer versions. The version numbers are multiples of 100. For example, + * version 1.2.3 is converted to 1020300 -- the last two digits are reserved + * for future use. + * + * The result of this function can be used in comparing the version number + * in a calling program if version-specific calls need to be make. + * + * Return: Version number of kcapi library + */ +JENT_PRIVATE_STATIC +unsigned int jent_version(void) +{ + unsigned int version = 0; + + version = MAJVERSION * 1000000; + version += MINVERSION * 10000; + version += PATCHLEVEL * 100; + + return version; +} + +/** + * Update of the loop count used for the next round of + * an entropy collection. + * + * Input: + * @ec entropy collector struct -- may be NULL + * @bits is the number of low bits of the timer to consider + * @min is the number of bits we shift the timer value to the right at + * the end to make sure we have a guaranteed minimum value + * + * @return Newly calculated loop counter + */ +static uint64_t jent_loop_shuffle(struct rand_data *ec, + unsigned int bits, unsigned int min) +{ + uint64_t time = 0; + uint64_t shuffle = 0; + unsigned int i = 0; + unsigned int mask = (1<<bits) - 1; + + jent_get_nstime(&time); + /* + * Mix the current state of the random number into the shuffle + * calculation to balance that shuffle a bit more. + */ + if (ec) + time ^= ec->data; + /* + * We fold the time value as much as possible to ensure that as many + * bits of the time stamp are included as possible. + */ + for (i = 0; (DATA_SIZE_BITS / bits) > i; i++) { + shuffle ^= time & mask; + time = time >> bits; + } + + /* + * We add a lower boundary value to ensure we have a minimum + * RNG loop count. + */ + return (shuffle + (1<<min)); +} + +/*************************************************************************** + * Noise sources + ***************************************************************************/ + +/** + * CPU Jitter noise source -- this is the noise source based on the CPU + * execution time jitter + * + * This function injects the individual bits of the time value into the + * entropy pool using an LFSR. + * + * The code is deliberately inefficient with respect to the bit shifting + * and shall stay that way. This function is the root cause why the code + * shall be compiled without optimization. This function not only acts as + * folding operation, but this function's execution is used to measure + * the CPU execution time jitter. Any change to the loop in this function + * implies that careful retesting must be done. + * + * Input: + * @ec entropy collector struct -- may be NULL + * @time time stamp to be injected + * @loop_cnt if a value not equal to 0 is set, use the given value as number of + * loops to perform the folding + * + * Output: + * updated ec->data + * + * @return Number of loops the folding operation is performed + */ +static uint64_t jent_lfsr_time(struct rand_data *ec, uint64_t time, + uint64_t loop_cnt) +{ + unsigned int i; + uint64_t j = 0; + uint64_t new = 0; +#define MAX_FOLD_LOOP_BIT 4 +#define MIN_FOLD_LOOP_BIT 0 + uint64_t fold_loop_cnt = + jent_loop_shuffle(ec, MAX_FOLD_LOOP_BIT, MIN_FOLD_LOOP_BIT); + + /* + * testing purposes -- allow test app to set the counter, not + * needed during runtime + */ + if (loop_cnt) + fold_loop_cnt = loop_cnt; + for (j = 0; j < fold_loop_cnt; j++) { + new = ec->data; + for (i = 1; (DATA_SIZE_BITS) >= i; i++) { + uint64_t tmp = time << (DATA_SIZE_BITS - i); + + tmp = tmp >> (DATA_SIZE_BITS - 1); + + /* + * Fibonacci LSFR with polynomial of + * x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is + * primitive according to + * http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf + * (the shift values are the polynomial values minus one + * due to counting bits from 0 to 63). As the current + * position is always the LSB, the polynomial only needs + * to shift data in from the left without wrap. + */ + new ^= tmp; + new ^= ((new >> 63) & 1); + new ^= ((new >> 60) & 1); + new ^= ((new >> 55) & 1); + new ^= ((new >> 30) & 1); + new ^= ((new >> 27) & 1); + new ^= ((new >> 22) & 1); + new = rol64(new, 1); + } + } + ec->data = new; + + return fold_loop_cnt; +} + +/** + * Memory Access noise source -- this is a noise source based on variations in + * memory access times + * + * This function performs memory accesses which will add to the timing + * variations due to an unknown amount of CPU wait states that need to be + * added when accessing memory. The memory size should be larger than the L1 + * caches as outlined in the documentation and the associated testing. + * + * The L1 cache has a very high bandwidth, albeit its access rate is usually + * slower than accessing CPU registers. Therefore, L1 accesses only add minimal + * variations as the CPU has hardly to wait. Starting with L2, significant + * variations are added because L2 typically does not belong to the CPU any more + * and therefore a wider range of CPU wait states is necessary for accesses. + * L3 and real memory accesses have even a wider range of wait states. However, + * to reliably access either L3 or memory, the ec->mem memory must be quite + * large which is usually not desirable. + * + * Input: + * @ec Reference to the entropy collector with the memory access data -- if + * the reference to the memory block to be accessed is NULL, this noise + * source is disabled + * @loop_cnt if a value not equal to 0 is set, use the given value as number of + * loops to perform the folding + * + * @return Number of memory access operations + */ +static unsigned int jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) +{ + unsigned int wrap = 0; + uint64_t i = 0; +#define MAX_ACC_LOOP_BIT 7 +#define MIN_ACC_LOOP_BIT 0 + uint64_t acc_loop_cnt = + jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); + + if (NULL == ec || NULL == ec->mem) + return 0; + wrap = ec->memblocksize * ec->memblocks; + + /* + * testing purposes -- allow test app to set the counter, not + * needed during runtime + */ + if (loop_cnt) + acc_loop_cnt = loop_cnt; + + for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { + unsigned char *tmpval = ec->mem + ec->memlocation; + /* + * memory access: just add 1 to one byte, + * wrap at 255 -- memory access implies read + * from and write to memory location + */ + *tmpval = (*tmpval + 1) & 0xff; + /* + * Addition of memblocksize - 1 to pointer + * with wrap around logic to ensure that every + * memory location is hit evenly + */ + ec->memlocation = ec->memlocation + ec->memblocksize - 1; + ec->memlocation = ec->memlocation % wrap; + } + return i; +} + +/*************************************************************************** + * Start of entropy processing logic + ***************************************************************************/ + +/** + * Stuck test by checking the: + * 1st derivation of the jitter measurement (time delta) + * 2nd derivation of the jitter measurement (delta of time deltas) + * 3rd derivation of the jitter measurement (delta of delta of time deltas) + * + * All values must always be non-zero. + * + * Input: + * @ec Reference to entropy collector + * @current_delta Jitter time delta + * + * @return + * 0 jitter measurement not stuck (good bit) + * 1 jitter measurement stuck (reject bit) + */ +static int jent_stuck(struct rand_data *ec, uint64_t current_delta) +{ + int64_t delta2 = ec->last_delta - current_delta; + int64_t delta3 = (uint64_t)delta2 - (uint64_t)ec->last_delta2; + + ec->last_delta = current_delta; + ec->last_delta2 = delta2; + + if (!current_delta || !delta2 || !delta3) + return 1; + + return 0; +} + +/** + * This is the heart of the entropy generation: calculate time deltas and + * use the CPU jitter in the time deltas. The jitter is injected into the + * entropy pool. + * + * WARNING: ensure that ->prev_time is primed before using the output + * of this function! This can be done by calling this function + * and not using its result. + * + * Input: + * @entropy_collector Reference to entropy collector + * + * @return: result of stuck test + */ +static int jent_measure_jitter(struct rand_data *ec) +{ + uint64_t time = 0; + uint64_t current_delta = 0; + int stuck; + + /* Invoke one noise source before time measurement to add variations */ + jent_memaccess(ec, 0); + + /* + * Get time stamp and calculate time delta to previous + * invocation to measure the timing variations + */ + jent_get_nstime(&time); + current_delta = time - ec->prev_time; + ec->prev_time = time; + + /* Now call the next noise sources which also injects the data */ + jent_lfsr_time(ec, current_delta, 0); + + /* Check whether we have a stuck measurement. */ + stuck = jent_stuck(ec, current_delta); + + /* + * Rotate the data buffer by a prime number (any odd number would + * do) to ensure that every bit position of the input time stamp + * has an even chance of being merged with a bit position in the + * entropy pool. We do not use one here as the adjacent bits in + * successive time deltas may have some form of dependency. The + * chosen value of 7 implies that the low 7 bits of the next + * time delta value is concatenated with the current time delta. + */ + if (!stuck) + ec->data = rol64(ec->data, 7); + + return stuck; +} + +/** + * Shuffle the pool a bit by mixing some value with a bijective function (XOR) + * into the pool. + * + * The function generates a mixer value that depends on the bits set and the + * location of the set bits in the random number generated by the entropy + * source. Therefore, based on the generated random number, this mixer value + * can have 2**64 different values. That mixer value is initialized with the + * first two SHA-1 constants. After obtaining the mixer value, it is XORed into + * the random number. + * + * The mixer value is not assumed to contain any entropy. But due to the XOR + * operation, it can also not destroy any entropy present in the entropy pool. + * + * Input: + * @entropy_collector Reference to entropy collector + */ +static void jent_stir_pool(struct rand_data *entropy_collector) +{ + /* + * to shut up GCC on 32 bit, we have to initialize the 64 variable + * with two 32 bit variables + */ + union c { + uint64_t uint64; + uint32_t uint32[2]; + }; + /* + * This constant is derived from the first two 32 bit initialization + * vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 + */ + union c constant; + /* + * The start value of the mixer variable is derived from the third + * and fourth 32 bit initialization vector of SHA-1 as defined in + * FIPS 180-4 section 5.3.1 + */ + union c mixer; + unsigned int i = 0; + + /* Ensure that the function implements a constant time operation. */ + union c throw_away; + + /* + * Store the SHA-1 constants in reverse order to make up the 64 bit + * value -- this applies to a little endian system, on a big endian + * system, it reverses as expected. But this really does not matter + * as we do not rely on the specific numbers. We just pick the SHA-1 + * constants as they have a good mix of bit set and unset. + */ + constant.uint32[1] = 0x67452301; + constant.uint32[0] = 0xefcdab89; + mixer.uint32[1] = 0x98badcfe; + mixer.uint32[0] = 0x10325476; + + for (i = 0; i < DATA_SIZE_BITS; i++) { + /* + * get the i-th bit of the input random number and only XOR + * the constant into the mixer value when that bit is set + */ + if ((entropy_collector->data >> i) & 1) + mixer.uint64 ^= constant.uint64; + else + throw_away.uint64 ^= constant.uint64; + mixer.uint64 = rol64(mixer.uint64, 1); + } + entropy_collector->data ^= mixer.uint64; +} + +/** + * Generator of one 64 bit random number + * Function fills rand_data->data + * + * Input: + * @ec Reference to entropy collector + */ +static void jent_gen_entropy(struct rand_data *ec) +{ + unsigned int k = 0; + + /* priming of the ->prev_time value */ + jent_measure_jitter(ec); + + while (1) { + /* If a stuck measurement is received, repeat measurement */ + if (jent_measure_jitter(ec)) + continue; + + /* + * We multiply the loop value with ->osr to obtain the + * oversampling rate requested by the caller + */ + if (++k >= (DATA_SIZE_BITS * ec->osr)) + break; + } + if (ec->stir) + jent_stir_pool(ec); +} + +/** + * The continuous test required by FIPS 140-2 -- the function automatically + * primes the test if needed. + * + * Return: + * 0 if FIPS test passed + * < 0 if FIPS test failed + */ +static int jent_fips_test(struct rand_data *ec) +{ + if (ec->fips_enabled == -1) + return 0; + + if (ec->fips_enabled == 0) { + if (!jent_fips_enabled()) { + ec->fips_enabled = -1; + return 0; + } else + ec->fips_enabled = 1; + } + + /* prime the FIPS test */ + if (!ec->old_data) { + ec->old_data = ec->data; + jent_gen_entropy(ec); + } + + if (ec->data == ec->old_data) + return -1; + + ec->old_data = ec->data; + + return 0; +} + +/** + * Entry function: Obtain entropy for the caller. + * + * This function invokes the entropy gathering logic as often to generate + * as many bytes as requested by the caller. The entropy gathering logic + * creates 64 bit per invocation. + * + * This function truncates the last 64 bit entropy value output to the exact + * size specified by the caller. + * + * Input: + * @ec Reference to entropy collector + * @data pointer to buffer for storing random data -- buffer must already + * exist + * @len size of the buffer, specifying also the requested number of random + * in bytes + * + * @return number of bytes returned when request is fulfilled or an error + * + * The following error codes can occur: + * -1 entropy_collector is NULL + * -2 FIPS test failed + */ +JENT_PRIVATE_STATIC +ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len) +{ + char *p = data; + size_t orig_len = len; + + if (NULL == ec) + return -1; + + while (0 < len) { + size_t tocopy; + + jent_gen_entropy(ec); + if (jent_fips_test(ec)) + return -2; + + if ((DATA_SIZE_BITS / 8) < len) + tocopy = (DATA_SIZE_BITS / 8); + else + tocopy = len; + memcpy(p, &ec->data, tocopy); + + len -= tocopy; + p += tocopy; + } + + /* + * To be on the safe side, we generate one more round of entropy + * which we do not give out to the caller. That round shall ensure + * that in case the calling application crashes, memory dumps, pages + * out, or due to the CPU Jitter RNG lingering in memory for long + * time without being moved and an attacker cracks the application, + * all he reads in the entropy pool is a value that is NEVER EVER + * being used for anything. Thus, he does NOT see the previous value + * that was returned to the caller for cryptographic purposes. + */ + /* + * If we use secured memory, do not use that precaution as the secure + * memory protects the entropy pool. Moreover, note that using this + * call reduces the speed of the RNG by up to half + */ +#ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY + jent_gen_entropy(ec); +#endif + return orig_len; +} + +/*************************************************************************** + * Initialization logic + ***************************************************************************/ + +JENT_PRIVATE_STATIC +struct rand_data *jent_entropy_collector_alloc(unsigned int osr, + unsigned int flags) +{ + struct rand_data *entropy_collector; + + entropy_collector = jent_zalloc(sizeof(struct rand_data)); + if (NULL == entropy_collector) + return NULL; + + if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) { + /* Allocate memory for adding variations based on memory + * access + */ + entropy_collector->mem = + (unsigned char *)jent_zalloc(JENT_MEMORY_SIZE); + if (NULL == entropy_collector->mem) { + jent_zfree(entropy_collector, sizeof(struct rand_data)); + return NULL; + } + entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE; + entropy_collector->memblocks = JENT_MEMORY_BLOCKS; + entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS; + } + + /* verify and set the oversampling rate */ + if (0 == osr) + osr = 1; /* minimum sampling rate is 1 */ + entropy_collector->osr = osr; + + entropy_collector->stir = 1; + if (flags & JENT_DISABLE_STIR) + entropy_collector->stir = 0; + if (flags & JENT_DISABLE_UNBIAS) + entropy_collector->disable_unbias = 1; + + /* fill the data pad with non-zero values */ + jent_gen_entropy(entropy_collector); + + return entropy_collector; +} + +JENT_PRIVATE_STATIC +void jent_entropy_collector_free(struct rand_data *entropy_collector) +{ + if (NULL != entropy_collector) { + if (NULL != entropy_collector->mem) { + jent_zfree(entropy_collector->mem, JENT_MEMORY_SIZE); + entropy_collector->mem = NULL; + } + jent_zfree(entropy_collector, sizeof(struct rand_data)); + } +} + +JENT_PRIVATE_STATIC +int jent_entropy_init(void) +{ + int i; + uint64_t delta_sum = 0; + uint64_t old_delta = 0; + int time_backwards = 0; + int count_mod = 0; + int count_stuck = 0; + struct rand_data ec; + + memset(&ec, 0, sizeof(ec)); + + /* We could perform statistical tests here, but the problem is + * that we only have a few loop counts to do testing. These + * loop counts may show some slight skew and we produce + * false positives. + * + * Moreover, only old systems show potentially problematic + * jitter entropy that could potentially be caught here. But + * the RNG is intended for hardware that is available or widely + * used, but not old systems that are long out of favor. Thus, + * no statistical tests. + */ + + /* + * We could add a check for system capabilities such as clock_getres or + * check for CONFIG_X86_TSC, but it does not make much sense as the + * following sanity checks verify that we have a high-resolution + * timer. + */ + /* + * TESTLOOPCOUNT needs some loops to identify edge systems. 100 is + * definitely too little. + */ +#define TESTLOOPCOUNT 300 +#define CLEARCACHE 100 + for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) { + uint64_t time = 0; + uint64_t time2 = 0; + uint64_t delta = 0; + unsigned int lowdelta = 0; + int stuck; + + /* Invoke core entropy collection logic */ + jent_get_nstime(&time); + ec.prev_time = time; + jent_lfsr_time(&ec, time, 0); + jent_get_nstime(&time2); + + /* test whether timer works */ + if (!time || !time2) + return ENOTIME; + delta = time2 - time; + /* + * test whether timer is fine grained enough to provide + * delta even when called shortly after each other -- this + * implies that we also have a high resolution timer + */ + if (!delta) + return ECOARSETIME; + + stuck = jent_stuck(&ec, delta); + + /* + * up to here we did not modify any variable that will be + * evaluated later, but we already performed some work. Thus we + * already have had an impact on the caches, branch prediction, + * etc. with the goal to clear it to get the worst case + * measurements. + */ + if (CLEARCACHE > i) + continue; + + if (stuck) + count_stuck++; + + /* test whether we have an increasing timer */ + if (!(time2 > time)) + time_backwards++; + + /* use 32 bit value to ensure compilation on 32 bit arches */ + lowdelta = time2 - time; + if (!(lowdelta % 100)) + count_mod++; + + /* + * ensure that we have a varying delta timer which is necessary + * for the calculation of entropy -- perform this check + * only after the first loop is executed as we need to prime + * the old_data value + */ + if (delta > old_delta) + delta_sum += (delta - old_delta); + else + delta_sum += (old_delta - delta); + old_delta = delta; + } + + /* + * we allow up to three times the time running backwards. + * CLOCK_REALTIME is affected by adjtime and NTP operations. Thus, + * if such an operation just happens to interfere with our test, it + * should not fail. The value of 3 should cover the NTP case being + * performed during our test run. + */ + if (3 < time_backwards) + return ENOMONOTONIC; + + /* + * Variations of deltas of time must on average be larger + * than 1 to ensure the entropy estimation + * implied with 1 is preserved + */ + if ((delta_sum) <= 1) + return EMINVARVAR; + + /* + * Ensure that we have variations in the time stamp below 10 for at least + * 10% of all checks -- on some platforms, the counter increments in + * multiples of 100, but not always + */ + if ((TESTLOOPCOUNT/10 * 9) < count_mod) + return ECOARSETIME; + + /* + * If we have more than 90% stuck results, then this Jitter RNG is + * likely to not work well. + */ + if (JENT_STUCK_INIT_THRES(TESTLOOPCOUNT) < count_stuck) + return ESTUCK; + + return 0; +} + +/*************************************************************************** + * Statistical test logic not compiled for regular operation + ***************************************************************************/ + +#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +/* + * Statistical test: return the time duration for the folding operation. If min + * is set, perform the given number of LFSR ops. Otherwise, allow the + * loop count shuffling to define the number of LFSR ops. + */ +JENT_PRIVATE_STATIC +uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min) +{ + uint64_t time = 0; + uint64_t time2 = 0; + + jent_get_nstime(&time); + jent_memaccess(ec, min); + jent_lfsr_time(ec, time, min); + jent_get_nstime(&time2); + return ((time2 - time)); +} +#endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */ diff --git a/comm/third_party/libgcrypt/random/jitterentropy.h b/comm/third_party/libgcrypt/random/jitterentropy.h new file mode 100644 index 0000000000..3b7d14a18e --- /dev/null +++ b/comm/third_party/libgcrypt/random/jitterentropy.h @@ -0,0 +1,148 @@ +/* + * Non-physical true random number generator based on timing jitter. + * + * Copyright Stephan Mueller <smueller@chronox.de>, 2014 + * + * License + * ======= + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef _JITTERENTROPY_H +#define _JITTERENTROPY_H + +#ifdef __KERNEL__ +#include "jitterentropy-base-kernel.h" +#else +#include "jitterentropy-base-user.h" +#endif /* __KERNEL__ */ + +/* The entropy pool */ +struct rand_data +{ + /* all data values that are vital to maintain the security + * of the RNG are marked as SENSITIVE. A user must not + * access that information while the RNG executes its loops to + * calculate the next random value. */ + uint64_t data; /* SENSITIVE Actual random number */ + uint64_t old_data; /* SENSITIVE Previous random number */ + uint64_t prev_time; /* SENSITIVE Previous time stamp */ +#define DATA_SIZE_BITS ((sizeof(uint64_t)) * 8) + uint64_t last_delta; /* SENSITIVE stuck test */ + int64_t last_delta2; /* SENSITIVE stuck test */ + unsigned int osr; /* Oversample rate */ + int fips_enabled; /* FIPS enabled? */ + unsigned int stir:1; /* Post-processing stirring */ + unsigned int disable_unbias:1; /* Deactivate Von-Neuman unbias */ +#define JENT_MEMORY_BLOCKS 64 +#define JENT_MEMORY_BLOCKSIZE 32 +#define JENT_MEMORY_ACCESSLOOPS 128 +#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE) + unsigned char *mem; /* Memory access location with size of + * memblocks * memblocksize */ + unsigned int memlocation; /* Pointer to byte in *mem */ + unsigned int memblocks; /* Number of memory blocks in *mem */ + unsigned int memblocksize; /* Size of one memory block in bytes */ + unsigned int memaccessloops; /* Number of memory accesses per random + * bit generation */ +}; + +/* Flags that can be used to initialize the RNG */ +#define JENT_DISABLE_STIR (1<<0) /* Disable stirring the entropy pool */ +#define JENT_DISABLE_UNBIAS (1<<1) /* Disable the Von-Neuman Unbiaser */ +#define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more + entropy, saves MEMORY_SIZE RAM for + entropy collector */ + +/* -- BEGIN Main interface functions -- */ + +#ifndef JENT_STUCK_INIT_THRES +/* + * Per default, not more than 90% of all measurements during initialization + * are allowed to be stuck. + * + * It is allowed to change this value as required for the intended environment. + */ +#define JENT_STUCK_INIT_THRES(x) (x/10 * 9) +#endif + +#ifdef JENT_PRIVATE_COMPILE +# define JENT_PRIVATE_STATIC static +#else /* JENT_PRIVATE_COMPILE */ +# define JENT_PRIVATE_STATIC +#endif + +/* Number of low bits of the time value that we want to consider */ +/* get raw entropy */ +JENT_PRIVATE_STATIC +ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len); +/* initialize an instance of the entropy collector */ +JENT_PRIVATE_STATIC +struct rand_data *jent_entropy_collector_alloc(unsigned int osr, + unsigned int flags); +/* clearing of entropy collector */ +JENT_PRIVATE_STATIC +void jent_entropy_collector_free(struct rand_data *entropy_collector); + +/* initialization of entropy collector */ +JENT_PRIVATE_STATIC +int jent_entropy_init(void); + +/* return version number of core library */ +JENT_PRIVATE_STATIC +unsigned int jent_version(void); + +/* -- END of Main interface functions -- */ + +/* -- BEGIN error codes for init function -- */ +#define ENOTIME 1 /* Timer service not available */ +#define ECOARSETIME 2 /* Timer too coarse for RNG */ +#define ENOMONOTONIC 3 /* Timer is not monotonic increasing */ +#define EMINVARIATION 4 /* Timer variations too small for RNG */ +#define EVARVAR 5 /* Timer does not produce variations of variations + (2nd derivation of time is zero) */ +#define EMINVARVAR 6 /* Timer variations of variations is too small */ +#define EPROGERR 7 /* Programming error */ +#define ESTUCK 8 /* Too many stuck results during init. */ + +/* -- BEGIN statistical test functions only complied with CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT -- */ + +#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +JENT_PRIVATE_STATIC +uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min); +#endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */ + +/* -- END of statistical test function -- */ + +#endif /* _JITTERENTROPY_H */ diff --git a/comm/third_party/libgcrypt/random/rand-internal.h b/comm/third_party/libgcrypt/random/rand-internal.h new file mode 100644 index 0000000000..3422156957 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rand-internal.h @@ -0,0 +1,148 @@ +/* rand-internal.h - header to glue the random functions + * Copyright (C) 1998, 2002 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + */ + +#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. */ +enum random_origins + { + RANDOM_ORIGIN_INIT = 0, /* Used only for initialization. */ + RANDOM_ORIGIN_EXTERNAL = 1, /* Added from an external source. */ + RANDOM_ORIGIN_FASTPOLL = 2, /* Fast random poll function. */ + RANDOM_ORIGIN_SLOWPOLL = 3, /* Slow poll function. */ + RANDOM_ORIGIN_EXTRAPOLL = 4 /* Used to mark an extra pool seed + due to a GCRY_VERY_STRONG_RANDOM + random request. */ + }; + +#define RANDOM_CONF_DISABLE_JENT 1 +#define RANDOM_CONF_ONLY_URANDOM 2 + + +/*-- random.c --*/ +unsigned int _gcry_random_read_conf (void); +void _gcry_random_progress (const char *what, int printchar, + int current, int total); + + +/*-- random-csprng.c --*/ +void _gcry_rngcsprng_initialize (int full); +void _gcry_rngcsprng_close_fds (void); +void _gcry_rngcsprng_dump_stats (void); +void _gcry_rngcsprng_secure_alloc (void); +void _gcry_rngcsprng_enable_quick_gen (void); +void _gcry_rngcsprng_set_daemon_socket (const char *socketname); +int _gcry_rngcsprng_use_daemon (int onoff); +int _gcry_rngcsprng_is_faked (void); +gcry_error_t _gcry_rngcsprng_add_bytes (const void *buf, size_t buflen, + int quality); +void *_gcry_rngcsprng_get_bytes (size_t nbytes, + enum gcry_random_level level); +void *_gcry_rngcsprng_get_bytes_secure (size_t nbytes, + enum gcry_random_level level); +void _gcry_rngcsprng_randomize (void *buffer, size_t length, + enum gcry_random_level level); +void _gcry_rngcsprng_set_seed_file (const char *name); +void _gcry_rngcsprng_update_seed_file (void); +void _gcry_rngcsprng_fast_poll (void); + +/*-- random-drbg.c --*/ +void _gcry_rngdrbg_inititialize (int full); +void _gcry_rngdrbg_close_fds (void); +void _gcry_rngdrbg_dump_stats (void); +int _gcry_rngdrbg_is_faked (void); +gcry_error_t _gcry_rngdrbg_add_bytes (const void *buf, size_t buflen, + int quality); +void _gcry_rngdrbg_randomize (void *buffer, size_t length, + enum gcry_random_level level); +gcry_error_t _gcry_rngdrbg_selftest (selftest_report_func_t report); + +/*-- random-system.c --*/ +void _gcry_rngsystem_initialize (int full); +void _gcry_rngsystem_close_fds (void); +void _gcry_rngsystem_dump_stats (void); +int _gcry_rngsystem_is_faked (void); +gcry_error_t _gcry_rngsystem_add_bytes (const void *buf, size_t buflen, + int quality); +void _gcry_rngsystem_randomize (void *buffer, size_t length, + enum gcry_random_level level); + + + +/*-- rndlinux.c --*/ +int _gcry_rndlinux_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); + +/*-- rndunix.c --*/ +int _gcry_rndunix_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); + +/*-- rndegd.c --*/ +int _gcry_rndegd_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); +int _gcry_rndegd_connect_socket (int nofail); + +/*-- rndw32.c --*/ +int _gcry_rndw32_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); +void _gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin ); + +/*-- rndw32ce.c --*/ +int _gcry_rndw32ce_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); +void _gcry_rndw32ce_gather_random_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin ); + +/*-- rndjent.c --*/ +size_t _gcry_rndjent_poll (void (*add)(const void*, + size_t, enum random_origins), + enum random_origins origin, + size_t length); +void _gcry_rndjent_dump_stats (void); +void _gcry_rndjent_fini (void); + +/*-- rndhw.c --*/ +int _gcry_rndhw_failed_p (void); +void _gcry_rndhw_poll_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin); +size_t _gcry_rndhw_poll_slow (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, size_t req_length); + + + +#endif /*G10_RAND_INTERNAL_H*/ diff --git a/comm/third_party/libgcrypt/random/random-csprng.c b/comm/third_party/libgcrypt/random/random-csprng.c new file mode 100644 index 0000000000..66f5786499 --- /dev/null +++ b/comm/third_party/libgcrypt/random/random-csprng.c @@ -0,0 +1,1367 @@ +/* random-csprng.c - CSPRNG style random number generator (libgcrypt classic) + * Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + * 2007, 2008, 2010, 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + This random number generator is modelled after the one described in + Peter Gutmann's 1998 Usenix Security Symposium paper: "Software + Generation of Practically Strong Random Numbers". See also chapter + 6 in his book "Cryptographic Security Architecture", New York, + 2004, ISBN 0-387-95387-6. + + Note that the acronym CSPRNG stands for "Continuously Seeded + PseudoRandom Number Generator" as used in Peter's implementation of + the paper and not only for "Cryptographically Secure PseudoRandom + Number Generator". + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#ifdef HAVE_GETHRTIME +#include <sys/times.h> +#endif +#ifdef HAVE_GETTIMEOFDAY +#include <sys/time.h> +#endif +#ifdef HAVE_GETRUSAGE +#include <sys/resource.h> +#endif +#ifdef __MINGW32__ +#include <process.h> +#endif +#include "g10lib.h" +#include "random.h" +#include "rand-internal.h" +#include "cipher.h" /* _gcry_sha1_hash_buffer */ +#include "../cipher/sha1.h" /* _gcry_sha1_mixblock */ + +#ifndef RAND_MAX /* For SunOS. */ +#define RAND_MAX 32767 +#endif + +/* Check whether we can lock the seed file read write. */ +#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM) +#define LOCK_SEED_FILE 1 +#else +#define LOCK_SEED_FILE 0 +#endif + +/* Define the constant we use for transforming the pool at read-out. */ +#if SIZEOF_UNSIGNED_LONG == 8 +#define ADD_VALUE 0xa5a5a5a5a5a5a5a5 +#elif SIZEOF_UNSIGNED_LONG == 4 +#define ADD_VALUE 0xa5a5a5a5 +#else +#error weird size for an unsigned long +#endif + +/* Contstants pertaining to the hash pool. */ +#define BLOCKLEN 64 /* Hash this amount of bytes... */ +#define DIGESTLEN 20 /* ... into a digest of this length (sha-1). */ +/* POOLBLOCKS is the number of digests which make up the pool. */ +#define POOLBLOCKS 30 +/* POOLSIZE must be a multiple of the digest length to make the AND + operations faster, the size should also be a multiple of unsigned + long. */ +#define POOLSIZE (POOLBLOCKS*DIGESTLEN) +#if (POOLSIZE % SIZEOF_UNSIGNED_LONG) +#error Please make sure that poolsize is a multiple of unsigned long +#endif +#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG) + + +/* RNDPOOL is the pool we use to collect the entropy and to stir it + up. Its allocated size is POOLSIZE+BLOCKLEN. Note that this is + also an indication on whether the module has been fully + initialized. */ +static unsigned char *rndpool; + +/* KEYPOOL is used as a scratch copy to read out random from RNDPOOL. + Its allocated size is also POOLSIZE+BLOCKLEN. */ +static unsigned char *keypool; + +/* This is the offset into RNDPOOL where the next random bytes are to + be mixed in. */ +static size_t pool_writepos; + +/* When reading data out of KEYPOOL, we start the read at different + positions. This variable keeps track on where to read next. */ +static size_t pool_readpos; + +/* This flag is set to true as soon as the pool has been completely + filled the first time. This may happen either by reading a seed + file or by adding enough entropy. */ +static int pool_filled; + +/* This counter is used to track whether the initial seeding has been + done with enough bytes from a reliable entropy source. */ +static size_t pool_filled_counter; + +/* If random of level GCRY_VERY_STRONG_RANDOM has been requested we + have stricter requirements on what kind of entropy is in the pool. + In particular POOL_FILLED is not sufficient. Thus we add some + extra seeding and set this flag to true if the extra seeding has + been done. */ +static int did_initial_extra_seeding; + +/* This variable is used to estimated the amount of fresh entropy + available in RNDPOOL. */ +static int pool_balance; + +/* After a mixing operation this variable will be set to true and + cleared if new entropy has been added or a remix is required for + other reasons. */ +static int just_mixed; + +/* The name of the seed file or NULL if no seed file has been defined. + The seed file needs to be registered at initialization time. We + keep a malloced copy here. */ +static char *seed_file_name; + +/* If a seed file has been registered and maybe updated on exit this + flag set. */ +static int allow_seed_file_update; + +/* Option flag set at initialiation time to force allocation of the + pool in secure memory. */ +static int secure_alloc; + +/* This function pointer is set to the actual entropy gathering + function during initialization. After initialization it is + guaranteed to point to function. (On systems without a random + gatherer module a dummy function is used).*/ +static int (*slow_gather_fnc)(void (*)(const void*, size_t, + enum random_origins), + enum random_origins, size_t, int); + +/* This function is set to the actual fast entropy gathering function + during initialization. If it is NULL, no such function is + available. */ +static void (*fast_gather_fnc)(void (*)(const void*, size_t, + enum random_origins), + enum random_origins); + + +/* Option flag useful for debugging and the test suite. If set + requests for very strong random are degraded to strong random. Not + used by regular applications. */ +static int quick_test; + +/* This is the lock we use to protect all pool operations. */ +GPGRT_LOCK_DEFINE (pool_lock); + +/* This is a helper for assert calls. These calls are used to assert + that functions are called in a locked state. It is not meant to be + thread-safe but as a method to get aware of missing locks in the + test suite. */ +static int pool_is_locked; + + +/* We keep some counters in this structure for the sake of the + _gcry_random_dump_stats () function. */ +static struct +{ + unsigned long mixrnd; + unsigned long mixkey; + unsigned long slowpolls; + unsigned long fastpolls; + unsigned long getbytes1; + unsigned long ngetbytes1; + unsigned long getbytes2; + unsigned long ngetbytes2; + unsigned long addbytes; + unsigned long naddbytes; +} rndstats; + + + +/* --- Stuff pertaining to the random daemon support. --- */ +#ifdef USE_RANDOM_DAEMON + +/* If ALLOW_DAEMON is true, the module will try to use the random + daemon first. If the daemon has failed, this variable is set to + back to false and the code continues as normal. Note, we don't + test this flag in a locked state because a wrong value does not + harm and the trhead will find out itself that the daemon does not + work and set it (again) to false. */ +static int allow_daemon; + +/* During initialization, the user may set a non-default socket name + for accessing the random daemon. If this value is NULL, the + default name will be used. */ +static char *daemon_socket_name; + +#endif /*USE_RANDOM_DAEMON*/ + + + +/* --- Prototypes --- */ +static void read_pool (byte *buffer, size_t length, int level ); +static void add_randomness (const void *buffer, size_t length, + enum random_origins origin); +static void random_poll (void); +static void do_fast_random_poll (void); +static int (*getfnc_gather_random (void))(void (*)(const void*, size_t, + enum random_origins), + enum random_origins, size_t, int); +static void (*getfnc_fast_random_poll (void))(void (*)(const void*, size_t, + enum random_origins), + enum random_origins); +static void read_random_source (enum random_origins origin, + size_t length, int level); + + + +/* --- Functions --- */ + + +/* Basic initialization which is required to initialize mutexes and + such. It does not run a full initialization so that the filling of + the random pool can be delayed until it is actually needed. We + assume that this function is used before any concurrent access + happens. */ +static void +initialize_basics(void) +{ + static int initialized; + + if (!initialized) + { + initialized = 1; + +#ifdef USE_RANDOM_DAEMON + _gcry_daemon_initialize_basics (); +#endif /*USE_RANDOM_DAEMON*/ + + /* Make sure that we are still using the values we have + traditionally used for the random levels. */ + gcry_assert (GCRY_WEAK_RANDOM == 0 + && GCRY_STRONG_RANDOM == 1 + && GCRY_VERY_STRONG_RANDOM == 2); + } +} + +/* Take the pool lock. */ +static void +lock_pool (void) +{ + int err; + + err = gpgrt_lock_lock (&pool_lock); + if (err) + log_fatal ("failed to acquire the pool lock: %s\n", gpg_strerror (err)); + pool_is_locked = 1; +} + +/* Release the pool lock. */ +static void +unlock_pool (void) +{ + int err; + + pool_is_locked = 0; + err = gpgrt_lock_unlock (&pool_lock); + if (err) + log_fatal ("failed to release the pool lock: %s\n", gpg_strerror (err)); +} + + +/* Full initialization of this module. */ +static void +initialize(void) +{ + /* Although the basic initialization should have happened already, + we call it here to make sure that all prerequisites are met. */ + initialize_basics (); + + /* Now we can look the pool and complete the initialization if + necessary. */ + lock_pool (); + if (!rndpool) + { + /* The data buffer is allocated somewhat larger, so that we can + use this extra space (which is allocated in secure memory) as + a temporary hash buffer */ + rndpool = (secure_alloc + ? xcalloc_secure (1, POOLSIZE + BLOCKLEN) + : xcalloc (1, POOLSIZE + BLOCKLEN)); + keypool = (secure_alloc + ? xcalloc_secure (1, POOLSIZE + BLOCKLEN) + : xcalloc (1, POOLSIZE + BLOCKLEN)); + + /* Setup the slow entropy gathering function. The code requires + that this function exists. */ + slow_gather_fnc = getfnc_gather_random (); + + /* Setup the fast entropy gathering function. */ + fast_gather_fnc = getfnc_fast_random_poll (); + + } + unlock_pool (); +} + + + + +/* Initialize this random subsystem. If FULL is false, this function + merely calls the initialize and does not do anything more. Doing + this is not really required but when running in a threaded + environment we might get a race condition otherwise. */ +void +_gcry_rngcsprng_initialize (int full) +{ + if (!full) + initialize_basics (); + else + initialize (); +} + + +/* Try to close the FDs of the random gather module. This is + currently only implemented for rndlinux. */ +void +_gcry_rngcsprng_close_fds (void) +{ + lock_pool (); +#if USE_RNDLINUX + _gcry_rndlinux_gather_random (NULL, 0, 0, 0); + pool_filled = 0; /* Force re-open on next use. */ +#endif + unlock_pool (); +} + + +void +_gcry_rngcsprng_dump_stats (void) +{ + /* In theory we would need to lock the stats here. However this + function is usually called during cleanup and then we _might_ run + into problems. */ + + log_info ("random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n" + " outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu%s\n", + POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls, + rndstats.naddbytes, rndstats.addbytes, + rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1, + rndstats.ngetbytes2, rndstats.getbytes2, + _gcry_rndhw_failed_p()? " (hwrng failed)":""); +} + + +/* This function should be called during initialization and before + initialization of this module to place the random pools into secure + memory. */ +void +_gcry_rngcsprng_secure_alloc (void) +{ + secure_alloc = 1; +} + + +/* This may be called before full initialization to degrade the + quality of the RNG for the sake of a faster running test suite. */ +void +_gcry_rngcsprng_enable_quick_gen (void) +{ + quick_test = 1; +} + + +void +_gcry_rngcsprng_set_daemon_socket (const char *socketname) +{ +#ifdef USE_RANDOM_DAEMON + if (daemon_socket_name) + BUG (); + + daemon_socket_name = gcry_xstrdup (socketname); +#else /*!USE_RANDOM_DAEMON*/ + (void)socketname; +#endif /*!USE_RANDOM_DAEMON*/ +} + +/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set + to 0, disable the use of the daemon. With ONOF set to -1, return + whether the daemon has been enabled. */ +int +_gcry_rngcsprng_use_daemon (int onoff) +{ +#ifdef USE_RANDOM_DAEMON + int last; + + /* This is not really thread safe. However it is expected that this + function is being called during initialization and at that point + we are for other reasons not really thread safe. We do not want + to lock it because we might eventually decide that this function + may even be called prior to gcry_check_version. */ + last = allow_daemon; + if (onoff != -1) + allow_daemon = onoff; + + return last; +#else /*!USE_RANDOM_DAEMON*/ + (void)onoff; + return 0; +#endif /*!USE_RANDOM_DAEMON*/ +} + + +/* This function returns true if no real RNG is available or the + quality of the RNG has been degraded for test purposes. */ +int +_gcry_rngcsprng_is_faked (void) +{ + /* We need to initialize due to the runtime determination of + available entropy gather modules. */ + initialize(); + return quick_test; +} + + +/* 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. */ +gcry_error_t +_gcry_rngcsprng_add_bytes (const void *buf, size_t buflen, int quality) +{ + size_t nbytes; + const char *bufptr; + + if (quality == -1) + quality = 35; + else if (quality > 100) + quality = 100; + else if (quality < 0) + quality = 0; + + if (!buf) + return gpg_error (GPG_ERR_INV_ARG); + + if (!buflen || quality < 10) + return 0; /* Take a shortcut. */ + + /* Because we don't increment the entropy estimation with FASTPOLL, + we don't need to take lock that estimation while adding from an + external source. This limited entropy estimation also means that + we can't take QUALITY into account. */ + initialize_basics (); + bufptr = buf; + while (buflen) + { + nbytes = buflen > POOLSIZE? POOLSIZE : buflen; + lock_pool (); + if (rndpool) + add_randomness (bufptr, nbytes, RANDOM_ORIGIN_EXTERNAL); + unlock_pool (); + bufptr += nbytes; + buflen -= nbytes; + } + return 0; +} + + +/* Public function to fill the buffer with LENGTH bytes of + cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is + not very strong, GCRY_STRONG_RANDOM is strong enough for most + usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but + may be very slow. */ +void +_gcry_rngcsprng_randomize (void *buffer, size_t length, + enum gcry_random_level level) +{ + unsigned char *p; + + /* Make sure we are initialized. */ + initialize (); + + /* Handle our hack used for regression tests of Libgcrypt. */ + if ( quick_test && level > GCRY_STRONG_RANDOM ) + level = GCRY_STRONG_RANDOM; + + /* Make sure the level is okay. */ + level &= 3; + +#ifdef USE_RANDOM_DAEMON + if (allow_daemon + && !_gcry_daemon_randomize (daemon_socket_name, buffer, length, level)) + return; /* The daemon succeeded. */ + allow_daemon = 0; /* Daemon failed - switch off. */ +#endif /*USE_RANDOM_DAEMON*/ + + /* Acquire the pool lock. */ + lock_pool (); + + /* Update the statistics. */ + if (level >= GCRY_VERY_STRONG_RANDOM) + { + rndstats.getbytes2 += length; + rndstats.ngetbytes2++; + } + else + { + rndstats.getbytes1 += length; + rndstats.ngetbytes1++; + } + + /* Read the random into the provided buffer. */ + for (p = buffer; length > 0;) + { + size_t n; + + n = length > POOLSIZE? POOLSIZE : length; + read_pool (p, n, level); + length -= n; + p += n; + } + + /* Release the pool lock. */ + unlock_pool (); +} + + + + +/* + * Mix the 600 byte pool. Note that the 64 byte scratch area directly + * follows the pool. The numbers in the diagram give the number of + * bytes. + * <................600...............> <.64.> + * pool |------------------------------------| |------| + * <20><.24.> <20> + * | | +-----+ + * +-----|-------------------------------|-+ + * +-------------------------------|-|-+ + * v v v + * |------| + * <hash> + * +---------------------------------------+ + * v + * <20> + * pool' |------------------------------------| + * <20><20><.24.> + * +---|-----|---------------------------+ + * +-----|---------------------------|-+ + * +---------------------------|-|-+ + * v v v + * |------| + * <hash> + * | + * +-----------------------------------+ + * v + * <20> + * pool'' |------------------------------------| + * <20><20><20><.24.> + * +---|-----|-----------------------+ + * +-----|-----------------------|-+ + * +-----------------------|-|-+ + * v v v + * + * and so on until we did this for all 30 blocks. + * + * To better protect against implementation errors in this code, we + * xor a digest of the entire pool into the pool before mixing. + * + * Note: this function must only be called with a locked pool. + */ +static void +mix_pool(unsigned char *pool) +{ + static unsigned char failsafe_digest[DIGESTLEN]; + static int failsafe_digest_valid; + + unsigned char *hashbuf = pool + POOLSIZE; + unsigned char *p, *pend; + int i, n; + SHA1_CONTEXT md; + unsigned int nburn; + +#if DIGESTLEN != 20 +#error must have a digest length of 20 for SHA-1 +#endif + + gcry_assert (pool_is_locked); + _gcry_sha1_mixblock_init (&md); + + /* pool_0 -> pool'. */ + pend = pool + POOLSIZE; + memcpy (hashbuf, pend - DIGESTLEN, DIGESTLEN); + memcpy (hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN); + nburn = _gcry_sha1_mixblock (&md, hashbuf); + memcpy (pool, hashbuf, DIGESTLEN); + + if (failsafe_digest_valid && pool == rndpool) + { + for (i=0; i < DIGESTLEN; i++) + pool[i] ^= failsafe_digest[i]; + } + + /* Loop for the remaining iterations. */ + p = pool; + for (n=1; n < POOLBLOCKS; n++) + { + if (p + BLOCKLEN < pend) + memcpy (hashbuf, p, BLOCKLEN); + else + { + unsigned char *pp = p; + + for (i=0; i < BLOCKLEN; i++ ) + { + if ( pp >= pend ) + pp = pool; + hashbuf[i] = *pp++; + } + } + + _gcry_sha1_mixblock (&md, hashbuf); + p += DIGESTLEN; + memcpy (p, hashbuf, DIGESTLEN); + } + + /* Our hash implementation does only leave small parts (64 bytes) + of the pool on the stack, so it is okay not to require secure + memory here. Before we use this pool, it will be copied to the + help buffer anyway. */ + if ( pool == rndpool) + { + _gcry_sha1_hash_buffer (failsafe_digest, pool, POOLSIZE); + failsafe_digest_valid = 1; + } + + _gcry_burn_stack (nburn); +} + + +void +_gcry_rngcsprng_set_seed_file (const char *name) +{ + if (seed_file_name) + BUG (); + seed_file_name = xstrdup (name); +} + + + +/* Helper for my_open. + * Return a malloced wide char string from an UTF-8 encoded input + * string STRING. Caller must free this value. Returns NULL and sets + * ERRNO on failure. Calling this function with STRING set to NULL is + * not defined. */ +#ifdef HAVE_W32_SYSTEM +static wchar_t * +utf8_to_wchar (const char *string) +{ + int n; + size_t nbytes; + wchar_t *result; + + n = MultiByteToWideChar (CP_UTF8, 0, string, -1, NULL, 0); + if (n < 0) + { + gpg_err_set_errno (EINVAL); + return NULL; + } + + nbytes = (size_t)(n+1) * sizeof(*result); + if (nbytes / sizeof(*result) != (n+1)) + { + gpg_err_set_errno (ENOMEM); + return NULL; + } + result = xtrymalloc (nbytes); + if (!result) + return NULL; + + n = MultiByteToWideChar (CP_UTF8, 0, string, -1, result, n); + if (n < 0) + { + xfree (result); + gpg_err_set_errno (EINVAL); + result = NULL; + } + return result; +} +#endif /*HAVE_W32_SYSTEM*/ + + +/* Helper for my_open. */ +#ifdef HAVE_W32_SYSTEM +static int +any8bitchar (const char *string) +{ + if (string) + for ( ; *string; string++) + if ((*string & 0x80)) + return 1; + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + +/* A wrapper around open to handle Unicode file names under Windows. */ +static int +my_open (const char *name, int flags, unsigned int mode) +{ +#ifdef HAVE_W32_SYSTEM + if (any8bitchar (name)) + { + wchar_t *wname; + int ret; + + wname = utf8_to_wchar (name); + if (!wname) + return -1; + ret = _wopen (wname, flags, mode); + xfree (wname); + return ret; + } + else + return open (name, flags, mode); +#else + return open (name, flags, mode); +#endif +} + + +/* Lock an open file identified by file descriptor FD and wait a + reasonable time to succeed. With FOR_WRITE set to true a write + lock will be taken. FNAME is used only for diagnostics. Returns 0 + on success or -1 on error. */ +static int +lock_seed_file (int fd, const char *fname, int for_write) +{ +#ifdef __GCC__ +#warning Check whether we can lock on Windows. +#endif +#if LOCK_SEED_FILE + struct flock lck; + struct timeval tv; + int backoff=0; + + /* We take a lock on the entire file. */ + memset (&lck, 0, sizeof lck); + lck.l_type = for_write? F_WRLCK : F_RDLCK; + lck.l_whence = SEEK_SET; + + while (fcntl (fd, F_SETLK, &lck) == -1) + { + if (errno != EAGAIN && errno != EACCES) + { + log_info (_("can't lock `%s': %s\n"), fname, strerror (errno)); + return -1; + } + + if (backoff > 2) /* Show the first message after ~2.25 seconds. */ + log_info( _("waiting for lock on `%s'...\n"), fname); + + tv.tv_sec = backoff; + tv.tv_usec = 250000; + select (0, NULL, NULL, NULL, &tv); + if (backoff < 10) + backoff++ ; + } +#else + (void)fd; + (void)fname; + (void)for_write; +#endif /*!LOCK_SEED_FILE*/ + return 0; +} + + +/* Read in a seed from the random_seed file and return true if this + was successful. + + Note: Multiple instances of applications sharing the same random + seed file can be started in parallel, in which case they will read + out the same pool and then race for updating it (the last update + overwrites earlier updates). They will differentiate only by the + weak entropy that is added in read_seed_file based on the PID and + clock, and up to 32 bytes from a non-blocking entropy source. The + consequence is that the output of these different instances is + correlated to some extent. In the perfect scenario, the attacker + can control (or at least guess) the PID and clock of the + application, and drain the system's entropy pool to reduce the "up + to 32 bytes" above to 0. Then the dependencies of the initial + states of the pools are completely known. */ +static int +read_seed_file (void) +{ + int fd; + struct stat sb; + unsigned char buffer[POOLSIZE]; + int n; + + gcry_assert (pool_is_locked); + + if (!seed_file_name) + return 0; + +#ifdef HAVE_DOSISH_SYSTEM + fd = my_open (seed_file_name, O_RDONLY | O_BINARY, 0); +#else + fd = my_open (seed_file_name, O_RDONLY, 0); +#endif + if( fd == -1 && errno == ENOENT) + { + allow_seed_file_update = 1; + return 0; + } + + if (fd == -1 ) + { + log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) ); + return 0; + } + if (lock_seed_file (fd, seed_file_name, 0)) + { + close (fd); + return 0; + } + if (fstat( fd, &sb ) ) + { + log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) ); + close(fd); + return 0; + } + if (!S_ISREG(sb.st_mode) ) + { + log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name ); + close(fd); + return 0; + } + if (!sb.st_size ) + { + log_info(_("note: random_seed file is empty\n") ); + close(fd); + allow_seed_file_update = 1; + return 0; + } + if (sb.st_size != POOLSIZE ) + { + log_info(_("warning: invalid size of random_seed file - not used\n") ); + close(fd); + return 0; + } + + do + { + n = read( fd, buffer, POOLSIZE ); + } + while (n == -1 && errno == EINTR ); + + if (n != POOLSIZE) + { + log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) ); + close(fd);/*NOTREACHED*/ + return 0; + } + + close(fd); + + add_randomness( buffer, POOLSIZE, RANDOM_ORIGIN_INIT ); + /* add some minor entropy to the pool now (this will also force a mixing) */ + { + pid_t x = getpid(); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT ); + } + { + time_t x = time(NULL); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT ); + } + { + clock_t x = clock(); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT ); + } + + /* And read a few bytes from our entropy source. If we have the + * Jitter RNG we can fast get a lot of entropy. Thus we read 1024 + * bits from that source. + * + * Without the Jitter RNG we keep the old method of reading only a + * few bytes usually from /dev/urandom which won't block. */ + if (_gcry_rndjent_get_version (NULL)) + read_random_source (RANDOM_ORIGIN_INIT, 128, GCRY_STRONG_RANDOM); + else + read_random_source (RANDOM_ORIGIN_INIT, 32, GCRY_STRONG_RANDOM); + + allow_seed_file_update = 1; + return 1; +} + + +void +_gcry_rngcsprng_update_seed_file (void) +{ + unsigned long *sp, *dp; + int fd, i; + + /* We do only a basic initialization so that we can lock the pool. + This is required to cope with the case that this function is + called by some cleanup code at a point where the RNG has never + been initialized. */ + initialize_basics (); + lock_pool (); + + if ( !seed_file_name || !rndpool || !pool_filled ) + { + unlock_pool (); + return; + } + if ( !allow_seed_file_update ) + { + unlock_pool (); + log_info(_("note: random_seed file not updated\n")); + return; + } + + /* At this point we know that there is something in the pool and + thus we can conclude that the pool has been fully initialized. */ + + + /* Copy the entropy pool to a scratch pool and mix both of them. */ + for (i=0,dp=(unsigned long*)(void*)keypool, sp=(unsigned long*)(void*)rndpool; + i < POOLWORDS; i++, dp++, sp++ ) + { + *dp = *sp + ADD_VALUE; + } + mix_pool(rndpool); rndstats.mixrnd++; + mix_pool(keypool); rndstats.mixkey++; + +#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__) + fd = my_open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, + S_IRUSR|S_IWUSR ); +#else +# if LOCK_SEED_FILE + fd = my_open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR ); +# else + fd = my_open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR ); +# endif +#endif + + if (fd == -1 ) + log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) ); + else if (lock_seed_file (fd, seed_file_name, 1)) + { + close (fd); + } +#if LOCK_SEED_FILE + else if (ftruncate (fd, 0)) + { + log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno)); + close (fd); + } +#endif /*LOCK_SEED_FILE*/ + else + { + do + { + i = write (fd, keypool, POOLSIZE ); + } + while (i == -1 && errno == EINTR); + if (i != POOLSIZE) + log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno)); + if (close(fd)) + log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno)); + } + + unlock_pool (); +} + + +/* Read random out of the pool. This function is the core of the + public random functions. Note that Level GCRY_WEAK_RANDOM is not + anymore handled special and in fact is an alias in the API for + level GCRY_STRONG_RANDOM. Must be called with the pool already + locked. */ +static void +read_pool (byte *buffer, size_t length, int level) +{ + int i; + unsigned long *sp, *dp; + /* The volatile is there to make sure the compiler does not optimize + the code away in case the getpid function is badly attributed. + Note that we keep a pid in a static variable as well as in a + stack based one; the latter is to detect ill behaving thread + libraries, ignoring the pool mutexes. */ + static volatile pid_t my_pid = (pid_t)(-1); + volatile pid_t my_pid2; + + gcry_assert (pool_is_locked); + + retry: + /* Get our own pid, so that we can detect a fork. */ + my_pid2 = getpid (); + if (my_pid == (pid_t)(-1)) + my_pid = my_pid2; + if ( my_pid != my_pid2 ) + { + /* We detected a plain fork; i.e. we are now the child. Update + the static pid and add some randomness. */ + pid_t x; + + my_pid = my_pid2; + x = my_pid; + add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT); + just_mixed = 0; /* Make sure it will get mixed. */ + } + + gcry_assert (pool_is_locked); + + /* Our code does not allow to extract more than POOLSIZE. Better + check it here. */ + if (length > POOLSIZE) + { + log_bug("too many random bits requested\n"); + } + + if (!pool_filled) + { + if (read_seed_file() ) + pool_filled = 1; + } + + /* For level 2 quality (key generation) we always make sure that the + pool has been seeded enough initially. */ + if (level == GCRY_VERY_STRONG_RANDOM && !did_initial_extra_seeding) + { + size_t needed; + + pool_balance = 0; + needed = length - pool_balance; + if (needed < 16) /* At least 128 bits. */ + needed = 16; + else if( needed > POOLSIZE ) + BUG (); + read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed, + GCRY_VERY_STRONG_RANDOM); + pool_balance += needed; + did_initial_extra_seeding = 1; + } + + /* For level 2 make sure that there is enough random in the pool. */ + if (level == GCRY_VERY_STRONG_RANDOM && pool_balance < length) + { + size_t needed; + + if (pool_balance < 0) + pool_balance = 0; + needed = length - pool_balance; + if (needed > POOLSIZE) + BUG (); + read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed, + GCRY_VERY_STRONG_RANDOM); + pool_balance += needed; + } + + /* Make sure the pool is filled. */ + while (!pool_filled) + random_poll(); + + /* Always do a fast random poll (we have to use the unlocked version). */ + do_fast_random_poll(); + + /* Mix the pid in so that we for sure won't deliver the same random + after a fork. */ + { + pid_t apid = my_pid; + add_randomness (&apid, sizeof (apid), RANDOM_ORIGIN_INIT); + } + + /* Mix the pool (if add_randomness() didn't it). */ + if (!just_mixed) + { + mix_pool(rndpool); + rndstats.mixrnd++; + } + + /* Create a new pool. */ + for(i=0,dp=(unsigned long*)(void*)keypool, sp=(unsigned long*)(void*)rndpool; + i < POOLWORDS; i++, dp++, sp++ ) + *dp = *sp + ADD_VALUE; + + /* Mix both pools. */ + mix_pool(rndpool); rndstats.mixrnd++; + mix_pool(keypool); rndstats.mixkey++; + + /* Read the requested data. We use a read pointer to read from a + different position each time. */ + while (length--) + { + *buffer++ = keypool[pool_readpos++]; + if (pool_readpos >= POOLSIZE) + pool_readpos = 0; + pool_balance--; + } + + if (pool_balance < 0) + pool_balance = 0; + + /* Clear the keypool. */ + memset (keypool, 0, POOLSIZE); + + /* We need to detect whether a fork has happened. A fork might have + an identical pool and thus the child and the parent could emit + the very same random number. This test here is to detect forks + in a multi-threaded process. It does not work with all thread + implementations in particular not with pthreads. However it is + good enough for GNU Pth. */ + if ( getpid () != my_pid2 ) + { + pid_t x = getpid(); + add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT); + just_mixed = 0; /* Make sure it will get mixed. */ + my_pid = x; /* Also update the static pid. */ + goto retry; + } +} + + + +/* Add LENGTH bytes of randomness from buffer to the pool. ORIGIN is + used to specify the randomness origin. This is one of the + RANDOM_ORIGIN_* values. */ +static void +add_randomness (const void *buffer, size_t length, enum random_origins origin) +{ + const unsigned char *p = buffer; + size_t count = 0; + + gcry_assert (pool_is_locked); + + rndstats.addbytes += length; + rndstats.naddbytes++; + while (length-- ) + { + rndpool[pool_writepos++] ^= *p++; + count++; + if (pool_writepos >= POOLSIZE ) + { + /* It is possible that we are invoked before the pool is + filled using an unreliable origin of entropy, for example + the fast random poll. To avoid flagging the pool as + filled in this case, we track the initial filling state + separately. See also the remarks about the seed file. */ + if (origin >= RANDOM_ORIGIN_SLOWPOLL && !pool_filled) + { + pool_filled_counter += count; + count = 0; + if (pool_filled_counter >= POOLSIZE) + pool_filled = 1; + } + pool_writepos = 0; + mix_pool(rndpool); rndstats.mixrnd++; + just_mixed = !length; + } + } +} + + + +static void +random_poll() +{ + rndstats.slowpolls++; + read_random_source (RANDOM_ORIGIN_SLOWPOLL, POOLSIZE/5, GCRY_STRONG_RANDOM); +} + + +/* Runtime determination of the slow entropy gathering module. */ +static int (* +getfnc_gather_random (void))(void (*)(const void*, size_t, + enum random_origins), + enum random_origins, size_t, int) +{ + int (*fnc)(void (*)(const void*, size_t, enum random_origins), + enum random_origins, size_t, int); + +#if USE_RNDLINUX + if ( !access (NAME_OF_DEV_RANDOM, R_OK) + && !access (NAME_OF_DEV_URANDOM, R_OK)) + { + fnc = _gcry_rndlinux_gather_random; + return fnc; + } +#endif + +#if USE_RNDEGD + if ( _gcry_rndegd_connect_socket (1) != -1 ) + { + fnc = _gcry_rndegd_gather_random; + return fnc; + } +#endif + +#if USE_RNDUNIX + fnc = _gcry_rndunix_gather_random; + return fnc; +#endif + +#if USE_RNDW32 + fnc = _gcry_rndw32_gather_random; + return fnc; +#endif + +#if USE_RNDW32CE + fnc = _gcry_rndw32ce_gather_random; + return fnc; +#endif + + log_fatal (_("no entropy gathering module detected\n")); + + return NULL; /*NOTREACHED*/ +} + +/* Runtime determination of the fast entropy gathering function. + (Currently a compile time method is used.) */ +static void (* +getfnc_fast_random_poll (void))( void (*)(const void*, size_t, + enum random_origins), + enum random_origins) +{ +#if USE_RNDW32 + return _gcry_rndw32_gather_random_fast; +#endif +#if USE_RNDW32CE + return _gcry_rndw32ce_gather_random_fast; +#endif + return NULL; +} + + + +static void +do_fast_random_poll (void) +{ + gcry_assert (pool_is_locked); + + rndstats.fastpolls++; + + if (fast_gather_fnc) + fast_gather_fnc (add_randomness, RANDOM_ORIGIN_FASTPOLL); + + /* Continue with the generic functions. */ +#if HAVE_GETHRTIME + { + hrtime_t tv; + tv = gethrtime(); + add_randomness( &tv, sizeof(tv), RANDOM_ORIGIN_FASTPOLL ); + } +#elif HAVE_GETTIMEOFDAY + { + struct timeval tv; + if( gettimeofday( &tv, NULL ) ) + BUG(); + add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL ); + add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), RANDOM_ORIGIN_FASTPOLL ); + } +#elif HAVE_CLOCK_GETTIME + { struct timespec tv; + if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 ) + BUG(); + add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL ); + add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), RANDOM_ORIGIN_FASTPOLL ); + } +#else /* use times */ +# ifndef HAVE_DOSISH_SYSTEM + { struct tms buf; + times( &buf ); + add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL ); + } +# endif +#endif + +#ifdef HAVE_GETRUSAGE +# ifdef RUSAGE_SELF + { + struct rusage buf; + /* QNX/Neutrino does return ENOSYS - so we just ignore it and add + whatever is in buf. In a chroot environment it might not work + at all (i.e. because /proc/ is not accessible), so we better + ignore all error codes and hope for the best. */ + getrusage (RUSAGE_SELF, &buf ); + add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL ); + memset( &buf, 0, sizeof buf ); + } +# else /*!RUSAGE_SELF*/ +# ifdef __GCC__ +# warning There is no RUSAGE_SELF on this system +# endif +# endif /*!RUSAGE_SELF*/ +#endif /*HAVE_GETRUSAGE*/ + + /* Time and clock are available on all systems - so we better do it + just in case one of the above functions didn't work. */ + { + time_t x = time(NULL); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL ); + } + { + clock_t x = clock(); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL ); + } + + /* If the system features a fast hardware RNG, read some bytes from + there. */ + _gcry_rndhw_poll_fast (add_randomness, RANDOM_ORIGIN_FASTPOLL); +} + + +/* The fast random pool function as called at some places in + libgcrypt. This is merely a wrapper to make sure that this module + is initialized and to lock the pool. Note, that this function is a + NOP unless a random function has been used or _gcry_initialize (1) + has been used. We use this hack so that the internal use of this + function in cipher_open and md_open won't start filling up the + random pool, even if no random will be required by the process. */ +void +_gcry_rngcsprng_fast_poll (void) +{ + initialize_basics (); + + lock_pool (); + if (rndpool) + { + /* Yes, we are fully initialized. */ + do_fast_random_poll (); + } + unlock_pool (); +} + + + +static void +read_random_source (enum random_origins origin, size_t length, int level) +{ + if ( !slow_gather_fnc ) + log_fatal ("Slow entropy gathering module not yet initialized\n"); + + if (slow_gather_fnc (add_randomness, origin, length, level) < 0) + log_fatal ("No way to gather entropy for the RNG\n"); +} diff --git a/comm/third_party/libgcrypt/random/random-daemon.c b/comm/third_party/libgcrypt/random/random-daemon.c new file mode 100644 index 0000000000..8ea4df285b --- /dev/null +++ b/comm/third_party/libgcrypt/random/random-daemon.c @@ -0,0 +1,336 @@ +/* random-daemon.c - Access to the external random daemon + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + The functions here are used by random.c to divert calls to an + external random number daemon. The actual daemon we use is + gcryptrnd. Such a daemon is useful to keep a persistent pool in + memory over invocations of a single application and to allow + prioritizing access to the actual entropy sources. The drawback is + that we need to use IPC (i.e. unix domain socket) to convey + sensitive data. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <errno.h> +#include <unistd.h> + +#include "g10lib.h" +#include "random.h" + + + +/* This is default socket name we use in case the provided socket name + is NULL. */ +#define RANDOM_DAEMON_SOCKET "/var/run/libgcrypt/S.gcryptrnd" + +/* The lock serializing access to the daemon. */ +GPGRT_LOCK_DEFINE (daemon_lock); + +/* The socket connected to the daemon. */ +static int daemon_socket = -1; + +/* Creates a socket connected to the daemon. On success, store the + socket fd in *SOCK. Returns error code. */ +static gcry_error_t +connect_to_socket (const char *socketname, int *sock) +{ + struct sockaddr_un *srvr_addr; + socklen_t addrlen; + gcry_error_t err; + int fd; + int rc; + + srvr_addr = NULL; + + /* Create a socket. */ + fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) + { + log_error ("can't create socket: %s\n", strerror (errno)); + err = gcry_error_from_errno (errno); + goto out; + } + + /* Set up address. */ + srvr_addr = gcry_malloc (sizeof *srvr_addr); + if (! srvr_addr) + { + log_error ("malloc failed: %s\n", strerror (errno)); + err = gcry_error_from_errno (errno); + goto out; + } + memset (srvr_addr, 0, sizeof *srvr_addr); + srvr_addr->sun_family = AF_UNIX; + if (strlen (socketname) + 1 >= sizeof (srvr_addr->sun_path)) + { + log_error ("socket name `%s' too long\n", socketname); + err = gcry_error (GPG_ERR_ENAMETOOLONG); + goto out; + } + strcpy (srvr_addr->sun_path, socketname); + addrlen = (offsetof (struct sockaddr_un, sun_path) + + strlen (srvr_addr->sun_path) + 1); + + /* Connect socket. */ + rc = connect (fd, (struct sockaddr *) srvr_addr, addrlen); + if (rc == -1) + { + log_error ("error connecting socket `%s': %s\n", + srvr_addr->sun_path, strerror (errno)); + err = gcry_error_from_errno (errno); + goto out; + } + + err = 0; + + out: + + gcry_free (srvr_addr); + if (err) + { + close (fd); + fd = -1; + } + *sock = fd; + + return err; +} + + +/* Initialize basics of this module. This should be viewed as a + constructor to prepare locking. */ +void +_gcry_daemon_initialize_basics (void) +{ + /* Not anymore required. */ +} + + + +/* Send LENGTH bytes of BUFFER to file descriptor FD. Returns 0 on + success or another value on write error. */ +static int +writen (int fd, const void *buffer, size_t length) +{ + ssize_t n; + + while (length) + { + do + n = ath_write (fd, buffer, length); + while (n < 0 && errno == EINTR); + if (n < 0) + { + log_error ("write error: %s\n", strerror (errno)); + return -1; /* write error */ + } + length -= n; + buffer = (const char*)buffer + n; + } + return 0; /* Okay */ +} + +static int +readn (int fd, void *buf, size_t buflen, size_t *ret_nread) +{ + size_t nleft = buflen; + int nread; + char *p; + + p = buf; + while (nleft > 0) + { + nread = ath_read (fd, buf, nleft); + if (nread < 0) + { + if (nread == EINTR) + nread = 0; + else + return -1; + } + else if (!nread) + break; /* EOF */ + nleft -= nread; + buf = (char*)buf + nread; + } + if (ret_nread) + *ret_nread = buflen - nleft; + return 0; +} + +/* This functions requests REQ_NBYTES from the daemon. If NONCE is + true, the data should be suited for a nonce. If NONCE is FALSE, + data of random level LEVEL will be generated. The retrieved random + data will be stored in BUFFER. Returns error code. */ +static gcry_error_t +call_daemon (const char *socketname, + void *buffer, size_t req_nbytes, int nonce, + enum gcry_random_level level) +{ + static int initialized; + unsigned char buf[255]; + gcry_error_t err = 0; + size_t nbytes; + size_t nread; + int rc; + + if (!req_nbytes) + return 0; + + gpgrt_lock_lock (&daemon_lock); + + /* Open the socket if that has not been done. */ + if (!initialized) + { + initialized = 1; + err = connect_to_socket (socketname ? socketname : RANDOM_DAEMON_SOCKET, + &daemon_socket); + if (err) + { + daemon_socket = -1; + log_info ("not using random daemon\n"); + gpgrt_lock_unlock (&daemon_lock); + return err; + } + } + + /* Check that we have a valid socket descriptor. */ + if ( daemon_socket == -1 ) + { + gpgrt_lock_unlock (&daemon_lock); + return gcry_error (GPG_ERR_INTERNAL); + } + + + /* Do the real work. */ + + do + { + /* Process in chunks. */ + nbytes = req_nbytes > sizeof (buf) ? sizeof (buf) : req_nbytes; + req_nbytes -= nbytes; + + /* Construct request. */ + buf[0] = 3; + if (nonce) + buf[1] = 10; + else if (level == GCRY_VERY_STRONG_RANDOM) + buf[1] = 12; + else if (level == GCRY_STRONG_RANDOM) + buf[1] = 11; + buf[2] = nbytes; + + /* Send request. */ + rc = writen (daemon_socket, buf, 3); + if (rc == -1) + { + err = gcry_error_from_errno (errno); + break; + } + + /* Retrieve response. */ + + rc = readn (daemon_socket, buf, 2, &nread); + if (rc == -1) + { + err = gcry_error_from_errno (errno); + log_error ("read error: %s\n", _gcry_strerror (err)); + break; + } + if (nread && buf[0]) + { + log_error ("random daemon returned error code %d\n", buf[0]); + err = gcry_error (GPG_ERR_INTERNAL); /* ? */ + break; + } + if (nread != 2) + { + log_error ("response too small\n"); + err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */ + break; + } + + /* if (1)*/ /* Do this in verbose mode? */ + /* log_info ("received response with %d bytes of data\n", buf[1]);*/ + + if (buf[1] < nbytes) + { + log_error ("error: server returned less bytes than requested\n"); + err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */ + break; + } + else if (buf[1] > nbytes) + { + log_error ("warning: server returned more bytes than requested\n"); + err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */ + break; + } + + assert (nbytes <= sizeof (buf)); + + rc = readn (daemon_socket, buf, nbytes, &nread); + if (rc == -1) + { + err = gcry_error_from_errno (errno); + log_error ("read error: %s\n", _gcry_strerror (err)); + break; + } + + if (nread != nbytes) + { + log_error ("too little random data read\n"); + err = gcry_error (GPG_ERR_INTERNAL); + break; + } + + /* Successfuly read another chunk of data. */ + memcpy (buffer, buf, nbytes); + buffer = ((char *) buffer) + nbytes; + } + while (req_nbytes); + + gpgrt_lock_unlock (&daemon_lock); + + return err; +} + +/* Internal function to fill BUFFER with LENGTH bytes of random. We + support GCRY_STRONG_RANDOM and GCRY_VERY_STRONG_RANDOM here. + Return 0 on success. */ +int +_gcry_daemon_randomize (const char *socketname, + void *buffer, size_t length, + enum gcry_random_level level) +{ + gcry_error_t err; + + err = call_daemon (socketname, buffer, length, 0, level); + + return err ? -1 : 0; +} + +/* END */ diff --git a/comm/third_party/libgcrypt/random/random-drbg.c b/comm/third_party/libgcrypt/random/random-drbg.c new file mode 100644 index 0000000000..6124f5fb6d --- /dev/null +++ b/comm/third_party/libgcrypt/random/random-drbg.c @@ -0,0 +1,2668 @@ +/* random-drbg.c - Deterministic Random Bits Generator + * Copyright 2014 Stephan Mueller <smueller@chronox.de> + * + * DRBG: Deterministic Random Bits Generator + * Based on NIST Recommended DRBG from NIST SP800-90A with the following + * properties: + * * CTR DRBG with DF with AES-128, AES-192, AES-256 cores + * * Hash DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores + * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores + * * with and without prediction resistance + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * LGPLv2+, in which case the provisions of the LGPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the LGPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * + * gcry_control GCRYCTL_DRBG_REINIT + * ================================ + * This control request re-initializes the DRBG completely, i.e. the entire + * state of the DRBG is zeroized (with two exceptions listed in + * GCRYCTL_DRBG_SET_ENTROPY). + * + * The control request takes the following values which influences how + * the DRBG is re-initialized: + * + * - const char *flagstr + * + * This variable specifies the DRBG type to be used for the next + * initialization. If set to NULL, the previous DRBG type is + * used for the initialization. If not NULL a space separated + * list of tokens with associated flag values is expected which + * are ORed to form the mandatory flags of the requested DRBG + * strength and cipher type. Optionally, the prediction + * resistance flag can be ORed into the flags variable. + * + * | String token | Flag value | + * |--------------+------------------------| + * | aes | DRBG_CTRAES | + * | serpent | DRBG_CTRSERPENT | + * | twofish | DRBG_CTRTWOFISH | + * | sha1 | DRBG_HASHSHA1 | + * | sha256 | DRBG_HASHSHA256 | + * | sha512 | DRBG_HASHSHA512 | + * | hmac | DRBG_HMAC | + * | sym128 | DRBG_SYM128 | + * | sym192 | DRBG_SYM192 | + * | sym256 | DRBG_SYM256 | + * | pr | DRBG_PREDICTION_RESIST | + * + * For example: + * + * - CTR-DRBG with AES-128 without prediction resistance: + * "aes sym128" + * - HMAC-DRBG with SHA-512 with prediction resistance: + * "hmac sha512 pr" + * + * - gcry_buffer_t *pers + * + * NULL terminated array with personalization strings to be used + * for initialization. + * + * - int npers + * + * Size of PERS. + * + * - void *guard + * + * A value of NULL must be passed for this. + * + * The variable of flags is independent from the pers/perslen variables. If + * flags is set to 0 and perslen is set to 0, the current DRBG type is + * completely reset without using a personalization string. + * + * DRBG Usage + * ========== + * The SP 800-90A DRBG allows the user to specify a personalization string + * for initialization as well as an additional information string for each + * random number request. The following code fragments show how a caller + * uses the API to use the full functionality of the DRBG. + * + * Usage without any additional data + * --------------------------------- + * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); + * + * + * Usage with personalization string during initialization + * ------------------------------------------------------- + * drbg_string_t pers; + * char personalization[11] = "some-string"; + * + * drbg_string_fill(&pers, personalization, strlen(personalization)); + * // The reset completely re-initializes the DRBG with the provided + * // personalization string without changing the DRBG type + * ret = gcry_control(GCRYCTL_DRBG_REINIT, 0, &pers); + * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); + * + * + * Usage with additional information string during random number request + * --------------------------------------------------------------------- + * drbg_string_t addtl; + * char addtl_string[11] = "some-string"; + * + * drbg_string_fill(&addtl, addtl_string, strlen(addtl_string)); + * // The following call is a wrapper to gcry_randomize() and returns + * // the same error codes. + * gcry_randomize_drbg(outbuf, OUTLEN, GCRY_STRONG_RANDOM, &addtl); + * + * + * Usage with personalization and additional information strings + * ------------------------------------------------------------- + * Just mix both scenarios above. + * + * + * Switch the DRBG type to some other type + * --------------------------------------- + * // Switch to CTR DRBG AES-128 without prediction resistance + * ret = gcry_control(GCRYCTL_DRBG_REINIT, DRBG_NOPR_CTRAES128, NULL); + * gcry_randomize(outbuf, OUTLEN, GCRY_STRONG_RANDOM); + */ + +#include <config.h> + +#include <string.h> +#include <unistd.h> +#include <stdint.h> + +#include "g10lib.h" +#include "random.h" +#include "rand-internal.h" +#include "../cipher/bufhelp.h" + + + +/****************************************************************** + * Constants + ******************************************************************/ + +/* + * DRBG flags bitmasks + * + * 31 (B) 28 19 (A) 0 + * +-+-+-+--------+---+-----------+-----+ + * |~|~|u|~~~~~~~~| 3 | 2 | 1 | + * +-+-+-+--------+- -+-----------+-----+ + * ctl flg| |drbg use selection flags + * + */ + +/* Internal state control flags (B) */ +#define DRBG_PREDICTION_RESIST ((u32)1<<28) + +/* CTR type modifiers (A.1)*/ +#define DRBG_CTRAES ((u32)1<<0) +#define DRBG_CTRSERPENT ((u32)1<<1) +#define DRBG_CTRTWOFISH ((u32)1<<2) +#define DRBG_CTR_MASK (DRBG_CTRAES | DRBG_CTRSERPENT \ + | DRBG_CTRTWOFISH) + +/* HASH type modifiers (A.2)*/ +#define DRBG_HASHSHA1 ((u32)1<<4) +#define DRBG_HASHSHA224 ((u32)1<<5) +#define DRBG_HASHSHA256 ((u32)1<<6) +#define DRBG_HASHSHA384 ((u32)1<<7) +#define DRBG_HASHSHA512 ((u32)1<<8) +#define DRBG_HASH_MASK (DRBG_HASHSHA1 | DRBG_HASHSHA224 \ + | DRBG_HASHSHA256 | DRBG_HASHSHA384 \ + | DRBG_HASHSHA512) +/* type modifiers (A.3)*/ +#define DRBG_HMAC ((u32)1<<12) +#define DRBG_SYM128 ((u32)1<<13) +#define DRBG_SYM192 ((u32)1<<14) +#define DRBG_SYM256 ((u32)1<<15) +#define DRBG_TYPE_MASK (DRBG_HMAC | DRBG_SYM128 | DRBG_SYM192 \ + | DRBG_SYM256) +#define DRBG_CIPHER_MASK (DRBG_CTR_MASK | DRBG_HASH_MASK \ + | DRBG_TYPE_MASK) + +#define DRBG_PR_CTRAES128 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM128) +#define DRBG_PR_CTRAES192 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM192) +#define DRBG_PR_CTRAES256 (DRBG_PREDICTION_RESIST | DRBG_CTRAES | DRBG_SYM256) +#define DRBG_NOPR_CTRAES128 (DRBG_CTRAES | DRBG_SYM128) +#define DRBG_NOPR_CTRAES192 (DRBG_CTRAES | DRBG_SYM192) +#define DRBG_NOPR_CTRAES256 (DRBG_CTRAES | DRBG_SYM256) +#define DRBG_PR_HASHSHA1 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1) +#define DRBG_PR_HASHSHA256 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256) +#define DRBG_PR_HASHSHA384 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384) +#define DRBG_PR_HASHSHA512 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512) +#define DRBG_NOPR_HASHSHA1 (DRBG_HASHSHA1) +#define DRBG_NOPR_HASHSHA256 (DRBG_HASHSHA256) +#define DRBG_NOPR_HASHSHA384 (DRBG_HASHSHA384) +#define DRBG_NOPR_HASHSHA512 (DRBG_HASHSHA512) +#define DRBG_PR_HMACSHA1 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA1 \ + | DRBG_HMAC) +#define DRBG_PR_HMACSHA256 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA256 \ + | DRBG_HMAC) +#define DRBG_PR_HMACSHA384 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA384 \ + | DRBG_HMAC) +#define DRBG_PR_HMACSHA512 (DRBG_PREDICTION_RESIST | DRBG_HASHSHA512 \ + | DRBG_HMAC) +#define DRBG_NOPR_HMACSHA1 (DRBG_HASHSHA1 | DRBG_HMAC) +#define DRBG_NOPR_HMACSHA256 (DRBG_HASHSHA256 | DRBG_HMAC) +#define DRBG_NOPR_HMACSHA384 (DRBG_HASHSHA384 | DRBG_HMAC) +#define DRBG_NOPR_HMACSHA512 (DRBG_HASHSHA512 | DRBG_HMAC) + + +/* The default DRGB type. */ +#define DRBG_DEFAULT_TYPE DRBG_NOPR_HMACSHA256 + + +#define DRBG_CTR_NULL_LEN 128 + + +/****************************************************************** + * Common data structures + ******************************************************************/ + +/* + * SP800-90A requires the concatenation of different data. To avoid copying + * buffers around or allocate additional memory, the following data structure + * is used to point to the original memory with its size. In addition, it + * is used to build a linked list. The linked list defines the concatenation + * of individual buffers. The order of memory block referenced in that + * linked list determines the order of concatenation. + */ +struct drbg_string_s +{ + const unsigned char *buf; + size_t len; + struct drbg_string_s *next; +}; +typedef struct drbg_string_s drbg_string_t; + + +/* DRBG input data structure for DRBG generate with additional + * information string. */ +struct drbg_gen_s +{ + unsigned char *outbuf; /* output buffer for random numbers */ + unsigned int outlen; /* size of output buffer */ + drbg_string_t *addtl; /* input buffer for + * additional information string */ +}; +typedef struct drbg_gen_s drbg_gen_t; + + +/* Forward declaration of the state object pointer. */ +struct drbg_state_s; +typedef struct drbg_state_s *drbg_state_t; + + +struct drbg_core_s +{ + u32 flags; /* flags for the cipher */ + ushort statelen; /* maximum state length */ + ushort blocklen_bytes; /* block size of output in bytes */ + int backend_cipher; /* libgcrypt backend cipher */ +}; + +struct drbg_state_ops_s +{ + gpg_err_code_t (*update) (drbg_state_t drbg, + drbg_string_t *seed, int reseed); + gpg_err_code_t (*generate) (drbg_state_t drbg, + unsigned char *buf, unsigned int buflen, + drbg_string_t *addtl); + gpg_err_code_t (*crypto_init) (drbg_state_t drbg); + void (*crypto_fini) (drbg_state_t drbg); +}; + +struct drbg_test_data_s +{ + drbg_string_t *testentropy; /* TEST PARAMETER: test entropy */ + int fail_seed_source:1; /* If set, the seed function will + * return an error. */ +}; + + +/* This state object keeps the state of an DRBG instance. */ +struct drbg_state_s +{ + unsigned char *V; /* internal state 10.1.1.1 1a) */ + unsigned char *C; /* hash: static value 10.1.1.1 1b) + * hmac / ctr: key */ + size_t reseed_ctr; /* Number of RNG requests since last reseed -- + * 10.1.1.1 1c) */ + unsigned char *scratchpad; /* some memory the DRBG can use for its + * operation -- allocated during init */ + void *priv_data; /* Cipher handle */ + gcry_cipher_hd_t ctr_handle; /* CTR mode cipher handle */ + int seeded:1; /* DRBG fully seeded? */ + int pr:1; /* Prediction resistance enabled? */ + /* Taken from libgcrypt ANSI X9.31 DRNG: We need to keep track of the + * process which did the initialization so that we can detect a fork. + * The volatile modifier is required so that the compiler does not + * optimize it away in case the getpid function is badly attributed. */ + pid_t seed_init_pid; + const struct drbg_state_ops_s *d_ops; + const struct drbg_core_s *core; + struct drbg_test_data_s *test_data; +}; + +enum drbg_prefixes +{ + DRBG_PREFIX0 = 0x00, + DRBG_PREFIX1, + DRBG_PREFIX2, + DRBG_PREFIX3 +}; + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +/*************************************************************** + * Global variables + ***************************************************************/ + +/* Global state variable holding the current instance of the DRBG. */ +static drbg_state_t drbg_state; + +/* This is the lock variable we use to serialize access to this RNG. */ +GPGRT_LOCK_DEFINE(drbg_lock_var); + + +/*************************************************************** + * Backend cipher definitions available to DRBG + ***************************************************************/ + +static const struct drbg_core_s drbg_cores[] = { + /* Hash DRBGs */ + {DRBG_HASHSHA1, 55, 20, GCRY_MD_SHA1}, + {DRBG_HASHSHA256, 55, 32, GCRY_MD_SHA256}, + {DRBG_HASHSHA384, 111, 48, GCRY_MD_SHA384}, + {DRBG_HASHSHA512, 111, 64, GCRY_MD_SHA512}, + /* HMAC DRBGs */ + {DRBG_HASHSHA1 | DRBG_HMAC, 20, 20, GCRY_MD_SHA1}, + {DRBG_HASHSHA256 | DRBG_HMAC, 32, 32, GCRY_MD_SHA256}, + {DRBG_HASHSHA384 | DRBG_HMAC, 48, 48, GCRY_MD_SHA384}, + {DRBG_HASHSHA512 | DRBG_HMAC, 64, 64, GCRY_MD_SHA512}, + /* block ciphers */ + {DRBG_CTRAES | DRBG_SYM128, 32, 16, GCRY_CIPHER_AES128}, + {DRBG_CTRAES | DRBG_SYM192, 40, 16, GCRY_CIPHER_AES192}, + {DRBG_CTRAES | DRBG_SYM256, 48, 16, GCRY_CIPHER_AES256} +}; + +static gpg_err_code_t drbg_hash_init (drbg_state_t drbg); +static gpg_err_code_t drbg_hmac_init (drbg_state_t drbg); +static gpg_err_code_t drbg_hmac_setkey (drbg_state_t drbg, + const unsigned char *key); +static void drbg_hash_fini (drbg_state_t drbg); +static byte *drbg_hash (drbg_state_t drbg, const drbg_string_t *buf); +static gpg_err_code_t drbg_sym_init (drbg_state_t drbg); +static void drbg_sym_fini (drbg_state_t drbg); +static gpg_err_code_t drbg_sym_setkey (drbg_state_t drbg, + const unsigned char *key); +static gpg_err_code_t drbg_sym (drbg_state_t drbg, unsigned char *outval, + const drbg_string_t *buf); +static gpg_err_code_t drbg_sym_ctr (drbg_state_t drbg, + const unsigned char *inbuf, unsigned int inbuflen, + unsigned char *outbuf, unsigned int outbuflen); + +/****************************************************************** + ****************************************************************** + ****************************************************************** + * Generic DRBG code + ****************************************************************** + ****************************************************************** + ******************************************************************/ + +/****************************************************************** + * Generic helper functions + ******************************************************************/ + +#if 0 +#define dbg(x) do { log_debug x; } while(0) +#else +#define dbg(x) +#endif + +/* + * Parse a string of flags and store the flag values at R_FLAGS. + * Return 0 on success. + */ +static gpg_err_code_t +parse_flag_string (const char *string, u32 *r_flags) +{ + struct { + const char *name; + u32 flag; + } table[] = { + { "aes", DRBG_CTRAES }, + { "serpent", DRBG_CTRSERPENT }, + { "twofish", DRBG_CTRTWOFISH }, + { "sha1", DRBG_HASHSHA1 }, + { "sha256", DRBG_HASHSHA256 }, + { "sha512", DRBG_HASHSHA512 }, + { "hmac", DRBG_HMAC }, + { "sym128", DRBG_SYM128 }, + { "sym192", DRBG_SYM192 }, + { "sym256", DRBG_SYM256 }, + { "pr", DRBG_PREDICTION_RESIST } + }; + + *r_flags = 0; + if (string) + { + char **tl; + const char *s; + int i, j; + + tl = _gcry_strtokenize (string, NULL); + if (!tl) + return gpg_err_code_from_syserror (); + for (i=0; (s=tl[i]); i++) + { + for (j=0; j < DIM (table); j++) + if (!strcmp (s, table[j].name)) + { + *r_flags |= table[j].flag; + break; + } + if (!(j < DIM (table))) + { + xfree (tl); + return GPG_ERR_INV_FLAG; + } + } + xfree (tl); + } + + return 0; +} + +static inline void +drbg_string_fill (drbg_string_t *string, + const unsigned char *buf, size_t len) +{ + string->buf = buf; + string->len = len; + string->next = NULL; +} + +static inline ushort +drbg_statelen (drbg_state_t drbg) +{ + if (drbg && drbg->core) + return drbg->core->statelen; + return 0; +} + +static inline ushort +drbg_blocklen (drbg_state_t drbg) +{ + if (drbg && drbg->core) + return drbg->core->blocklen_bytes; + return 0; +} + +static inline ushort +drbg_keylen (drbg_state_t drbg) +{ + if (drbg && drbg->core) + return (drbg->core->statelen - drbg->core->blocklen_bytes); + return 0; +} + +static inline size_t +drbg_max_request_bytes (void) +{ + /* SP800-90A requires the limit 2**19 bits, but we return bytes */ + return (1 << 16); +} + +static inline size_t +drbg_max_addtl (void) +{ + /* SP800-90A requires 2**35 bytes additional info str / pers str */ +#ifdef __LP64__ + return (1UL << 35); +#else + /* + * SP800-90A allows smaller maximum numbers to be returned -- we + * return SIZE_MAX - 1 to allow the verification of the enforcement + * of this value in drbg_healthcheck_sanity. + */ + return (SIZE_MAX - 1); +#endif +} + +static inline size_t +drbg_max_requests (void) +{ + /* SP800-90A requires 2**48 maximum requests before reseeding */ +#ifdef __LP64__ + return (1UL << 48); +#else + return SIZE_MAX; +#endif +} + +/* + * Return strength of DRBG according to SP800-90A section 8.4 + * + * flags: DRBG flags reference + * + * Return: normalized strength value or 32 as a default to counter + * programming errors + */ +static inline unsigned short +drbg_sec_strength (u32 flags) +{ + if ((flags & DRBG_HASHSHA1) || (flags & DRBG_SYM128)) + return 16; + else if (flags & DRBG_SYM192) + return 24; + else if ((flags & DRBG_SYM256) || (flags & DRBG_HASHSHA256) || + (flags & DRBG_HASHSHA384) || (flags & DRBG_HASHSHA512)) + return 32; + else + return 32; +} + +static void +drbg_add_buf (unsigned char *dst, size_t dstlen, + unsigned char *add, size_t addlen) +{ + /* implied: dstlen > addlen */ + unsigned char *dstptr, *addptr; + unsigned int remainder = 0; + size_t len = addlen; + + dstptr = dst + (dstlen - 1); + addptr = add + (addlen - 1); + while (len) + { + remainder += *dstptr + *addptr; + *dstptr = remainder & 0xff; + remainder >>= 8; + len--; + dstptr--; + addptr--; + } + len = dstlen - addlen; + while (len && remainder > 0) + { + remainder = *dstptr + 1; + *dstptr = remainder & 0xff; + remainder >>= 8; + len--; + dstptr--; + } +} + +/* Helper variables for read_cb(). + * + * The _gcry_rnd*_gather_random interface does not allow to provide a + * data pointer. Thus we need to use a global variable for + * communication. However, the then required locking is anyway a good + * idea because it does not make sense to have several readers of (say + * /dev/random). It is easier to serve them one after the other. + */ +static unsigned char *read_cb_buffer; /* The buffer. */ +static size_t read_cb_size; /* Size of the buffer. */ +static size_t read_cb_len; /* Used length. */ + +/* Callback for generating seed from kernel device. */ +static void +drbg_read_cb (const void *buffer, size_t length, + enum random_origins origin) +{ + const unsigned char *p = buffer; + + (void) origin; + gcry_assert (read_cb_buffer); + + /* Note that we need to protect against gatherers returning more + * than the requested bytes (e.g. rndw32). */ + while (length-- && read_cb_len < read_cb_size) + read_cb_buffer[read_cb_len++] = *p++; +} + +static inline int +drbg_get_entropy (drbg_state_t drbg, unsigned char *buffer, + size_t len) +{ + int rc = 0; + + /* Perform testing as defined in 11.3.2 */ + if (drbg->test_data && drbg->test_data->fail_seed_source) + return -1; + + read_cb_buffer = buffer; + read_cb_size = len; + read_cb_len = 0; +#if USE_RNDLINUX + rc = _gcry_rndlinux_gather_random (drbg_read_cb, 0, len, + GCRY_VERY_STRONG_RANDOM); +#elif USE_RNDUNIX + rc = _gcry_rndunix_gather_random (drbg_read_cb, 0, len, + GCRY_VERY_STRONG_RANDOM); +#elif USE_RNDW32 + do + { + rc = _gcry_rndw32_gather_random (drbg_read_cb, 0, len, + GCRY_VERY_STRONG_RANDOM); + } + while (rc >= 0 && read_cb_len < read_cb_size); +#else + rc = -1; +#endif + return rc; +} + +/****************************************************************** + * CTR DRBG callback functions + ******************************************************************/ + +/* BCC function for CTR DRBG as defined in 10.4.3 */ +static gpg_err_code_t +drbg_ctr_bcc (drbg_state_t drbg, + unsigned char *out, const unsigned char *key, + drbg_string_t *in) +{ + gpg_err_code_t ret = GPG_ERR_GENERAL; + drbg_string_t *curr = in; + size_t inpos = curr->len; + const unsigned char *pos = curr->buf; + drbg_string_t data; + + drbg_string_fill (&data, out, drbg_blocklen (drbg)); + + /* 10.4.3 step 1 */ + memset (out, 0, drbg_blocklen (drbg)); + + ret = drbg_sym_setkey(drbg, key); + if (ret) + return ret; + + /* 10.4.3 step 2 / 4 */ + while (inpos) + { + short cnt = 0; + /* 10.4.3 step 4.1 */ + for (cnt = 0; cnt < drbg_blocklen (drbg); cnt++) + { + out[cnt] ^= *pos; + pos++; + inpos--; + /* the following branch implements the linked list + * iteration. If we are at the end of the current data + * set, we have to start using the next data set if + * available -- the inpos value always points to the + * current byte and will be zero if we have processed + * the last byte of the last linked list member */ + if (0 == inpos) + { + curr = curr->next; + if (NULL != curr) + { + pos = curr->buf; + inpos = curr->len; + } + else + { + inpos = 0; + break; + } + } + } + /* 10.4.3 step 4.2 */ + ret = drbg_sym (drbg, out, &data); + if (ret) + return ret; + /* 10.4.3 step 2 */ + } + return 0; +} + + +/* + * scratchpad usage: drbg_ctr_update is interlinked with drbg_ctr_df + * (and drbg_ctr_bcc, but this function does not need any temporary buffers), + * the scratchpad is used as follows: + * drbg_ctr_update: + * temp + * start: drbg->scratchpad + * length: drbg_statelen(drbg) + drbg_blocklen(drbg) + * note: the cipher writing into this variable works + * blocklen-wise. Now, when the statelen is not a multiple + * of blocklen, the generateion loop below "spills over" + * by at most blocklen. Thus, we need to give sufficient + * memory. + * df_data + * start: drbg->scratchpad + + * drbg_statelen(drbg) + + * drbg_blocklen(drbg) + * length: drbg_statelen(drbg) + * + * drbg_ctr_df: + * pad + * start: df_data + drbg_statelen(drbg) + * length: drbg_blocklen(drbg) + * iv + * start: pad + drbg_blocklen(drbg) + * length: drbg_blocklen(drbg) + * temp + * start: iv + drbg_blocklen(drbg) + * length: drbg_satelen(drbg) + drbg_blocklen(drbg) + * note: temp is the buffer that the BCC function operates + * on. BCC operates blockwise. drbg_statelen(drbg) + * is sufficient when the DRBG state length is a multiple + * of the block size. For AES192 (and maybe other ciphers) + * this is not correct and the length for temp is + * insufficient (yes, that also means for such ciphers, + * the final output of all BCC rounds are truncated). + * Therefore, add drbg_blocklen(drbg) to cover all + * possibilities. + */ + +/* Derivation Function for CTR DRBG as defined in 10.4.2 */ +static gpg_err_code_t +drbg_ctr_df (drbg_state_t drbg, unsigned char *df_data, + size_t bytes_to_return, drbg_string_t *addtl) +{ + gpg_err_code_t ret = GPG_ERR_GENERAL; + unsigned char L_N[8]; + /* S3 is input */ + drbg_string_t S1, S2, S4, cipherin; + drbg_string_t *tempstr = addtl; + unsigned char *pad = df_data + drbg_statelen (drbg); + unsigned char *iv = pad + drbg_blocklen (drbg); + unsigned char *temp = iv + drbg_blocklen (drbg); + size_t padlen = 0; + unsigned int templen = 0; + /* 10.4.2 step 7 */ + unsigned int i = 0; + /* 10.4.2 step 8 */ + const unsigned char *K = (unsigned char *) + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"; + unsigned char *X; + size_t generated_len = 0; + size_t inputlen = 0; + + memset (pad, 0, drbg_blocklen (drbg)); + memset (iv, 0, drbg_blocklen (drbg)); + memset (temp, 0, drbg_statelen (drbg)); + + /* 10.4.2 step 1 is implicit as we work byte-wise */ + + /* 10.4.2 step 2 */ + if ((512 / 8) < bytes_to_return) + return GPG_ERR_INV_ARG; + + /* 10.4.2 step 2 -- calculate the entire length of all input data */ + for (; NULL != tempstr; tempstr = tempstr->next) + inputlen += tempstr->len; + buf_put_be32 (&L_N[0], inputlen); + + /* 10.4.2 step 3 */ + buf_put_be32 (&L_N[4], bytes_to_return); + + /* 10.4.2 step 5: length is size of L_N, input_string, one byte, padding */ + padlen = (inputlen + sizeof (L_N) + 1) % (drbg_blocklen (drbg)); + /* wrap the padlen appropriately */ + if (padlen) + padlen = drbg_blocklen (drbg) - padlen; + /* pad / padlen contains the 0x80 byte and the following zero bytes, so + * add one for byte for 0x80 */ + padlen++; + pad[0] = 0x80; + + /* 10.4.2 step 4 -- first fill the linked list and then order it */ + drbg_string_fill (&S1, iv, drbg_blocklen (drbg)); + drbg_string_fill (&S2, L_N, sizeof (L_N)); + drbg_string_fill (&S4, pad, padlen); + S1.next = &S2; + S2.next = addtl; + + /* Splice in addtl between S2 and S4 -- we place S4 at the end of the + * input data chain. As this code is only triggered when addtl is not + * NULL, no NULL checks are necessary.*/ + tempstr = addtl; + while (tempstr->next) + tempstr = tempstr->next; + tempstr->next = &S4; + + /* 10.4.2 step 9 */ + while (templen < (drbg_keylen (drbg) + (drbg_blocklen (drbg)))) + { + /* 10.4.2 step 9.1 - the padding is implicit as the buffer + * holds zeros after allocation -- even the increment of i + * is irrelevant as the increment remains within length of i */ + buf_put_be32 (iv, i); + /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ + ret = drbg_ctr_bcc (drbg, temp + templen, K, &S1); + if (ret) + goto out; + /* 10.4.2 step 9.3 */ + i++; + templen += drbg_blocklen (drbg); + } + + /* 10.4.2 step 11 */ + /* implicit key len with seedlen - blocklen according to table 3 */ + X = temp + (drbg_keylen (drbg)); + drbg_string_fill (&cipherin, X, drbg_blocklen (drbg)); + + /* 10.4.2 step 12: overwriting of outval */ + + /* 10.4.2 step 13 */ + ret = drbg_sym_setkey(drbg, temp); + if (ret) + goto out; + while (generated_len < bytes_to_return) + { + short blocklen = 0; + /* 10.4.2 step 13.1 */ + /* the truncation of the key length is implicit as the key + * is only drbg_blocklen in size -- check for the implementation + * of the cipher function callback */ + ret = drbg_sym (drbg, X, &cipherin); + if (ret) + goto out; + blocklen = (drbg_blocklen (drbg) < (bytes_to_return - generated_len)) ? + drbg_blocklen (drbg) : (bytes_to_return - generated_len); + /* 10.4.2 step 13.2 and 14 */ + memcpy (df_data + generated_len, X, blocklen); + generated_len += blocklen; + } + + ret = 0; + + out: + memset (iv, 0, drbg_blocklen (drbg)); + memset (temp, 0, drbg_statelen (drbg)); + memset (pad, 0, drbg_blocklen (drbg)); + return ret; +} + +/* + * Update function of CTR DRBG as defined in 10.2.1.2 + * + * The reseed variable has an enhanced meaning compared to the update + * functions of the other DRBGs as follows: + * 0 => initial seed from initialization + * 1 => reseed via drbg_seed + * 2 => first invocation from drbg_ctr_update when addtl is present. In + * this case, the df_data scratchpad is not deleted so that it is + * available for another calls to prevent calling the DF function + * again. + * 3 => second invocation from drbg_ctr_update. When the update function + * was called with addtl, the df_data memory already contains the + * DFed addtl information and we do not need to call DF again. + */ +static gpg_err_code_t +drbg_ctr_update (drbg_state_t drbg, drbg_string_t *addtl, int reseed) +{ + gpg_err_code_t ret = GPG_ERR_GENERAL; + /* 10.2.1.2 step 1 */ + unsigned char *temp = drbg->scratchpad; + unsigned char *df_data = drbg->scratchpad + + drbg_statelen (drbg) + drbg_blocklen (drbg); + unsigned char prefix = DRBG_PREFIX1; + + memset (temp, 0, drbg_statelen (drbg) + drbg_blocklen (drbg)); + if (3 > reseed) + memset (df_data, 0, drbg_statelen (drbg)); + + if (!reseed) + { + /* + * The DRBG uses the CTR mode of the underlying AES cipher. The + * CTR mode increments the counter value after the AES operation + * but SP800-90A requires that the counter is incremented before + * the AES operation. Hence, we increment it at the time we set + * it by one. + */ + drbg_add_buf (drbg->V, drbg_blocklen (drbg), &prefix, 1); + + ret = _gcry_cipher_setkey (drbg->ctr_handle, drbg->C, drbg_keylen (drbg)); + if (ret) + goto out; + } + + /* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */ + if (addtl && 0 < addtl->len) + { + ret = + drbg_ctr_df (drbg, df_data, drbg_statelen (drbg), addtl); + if (ret) + goto out; + } + + ret = drbg_sym_ctr (drbg, df_data, drbg_statelen(drbg), + temp, drbg_statelen(drbg)); + if (ret) + goto out; + + /* 10.2.1.2 step 5 */ + ret = _gcry_cipher_setkey (drbg->ctr_handle, temp, drbg_keylen (drbg)); + if (ret) + goto out; + + /* 10.2.1.2 step 6 */ + memcpy (drbg->V, temp + drbg_keylen (drbg), drbg_blocklen (drbg)); + /* See above: increment counter by one to compensate timing of CTR op */ + drbg_add_buf (drbg->V, drbg_blocklen (drbg), &prefix, 1); + ret = 0; + + out: + memset (temp, 0, drbg_statelen (drbg) + drbg_blocklen (drbg)); + if (2 != reseed) + memset (df_data, 0, drbg_statelen (drbg)); + return ret; +} + +/* + * scratchpad use: drbg_ctr_update is called independently from + * drbg_ctr_extract_bytes. Therefore, the scratchpad is reused + */ +/* Generate function of CTR DRBG as defined in 10.2.1.5.2 */ +static gpg_err_code_t +drbg_ctr_generate (drbg_state_t drbg, + unsigned char *buf, unsigned int buflen, + drbg_string_t *addtl) +{ + static const unsigned char drbg_ctr_null[DRBG_CTR_NULL_LEN] = { 0, }; + gpg_err_code_t ret = 0; + + memset (drbg->scratchpad, 0, drbg_blocklen (drbg)); + + /* 10.2.1.5.2 step 2 */ + if (addtl && 0 < addtl->len) + { + addtl->next = NULL; + ret = drbg_ctr_update (drbg, addtl, 2); + if (ret) + return ret; + } + + /* 10.2.1.5.2 step 4.1 */ + ret = drbg_sym_ctr (drbg, drbg_ctr_null, sizeof(drbg_ctr_null), buf, buflen); + if (ret) + goto out; + + /* 10.2.1.5.2 step 6 */ + if (addtl) + addtl->next = NULL; + ret = drbg_ctr_update (drbg, addtl, 3); + + out: + return ret; +} + +static struct drbg_state_ops_s drbg_ctr_ops = { + drbg_ctr_update, + drbg_ctr_generate, + drbg_sym_init, + drbg_sym_fini, +}; + +/****************************************************************** + * HMAC DRBG callback functions + ******************************************************************/ + +static gpg_err_code_t +drbg_hmac_update (drbg_state_t drbg, drbg_string_t *seed, int reseed) +{ + gpg_err_code_t ret = GPG_ERR_GENERAL; + int i = 0; + drbg_string_t seed1, seed2, cipherin; + + if (!reseed) + { + /* 10.1.2.3 step 2 already implicitly covered with + * the initial memset(0) of drbg->C */ + memset (drbg->V, 1, drbg_statelen (drbg)); + ret = drbg_hmac_setkey (drbg, drbg->C); + if (ret) + return ret; + } + + /* build linked list which implements the concatenation and fill + * first part*/ + drbg_string_fill (&seed1, drbg->V, drbg_statelen (drbg)); + /* buffer will be filled in for loop below with one byte */ + drbg_string_fill (&seed2, NULL, 1); + seed1.next = &seed2; + /* seed may be NULL */ + seed2.next = seed; + + drbg_string_fill (&cipherin, drbg->V, drbg_statelen (drbg)); + /* we execute two rounds of V/K massaging */ + for (i = 2; 0 < i; i--) + { + byte *retval; + /* first round uses 0x0, second 0x1 */ + unsigned char prefix = DRBG_PREFIX0; + if (1 == i) + prefix = DRBG_PREFIX1; + /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ + seed2.buf = &prefix; + retval = drbg_hash (drbg, &seed1); + ret = drbg_hmac_setkey (drbg, retval); + if (ret) + return ret; + + /* 10.1.2.2 step 2 and 5 -- HMAC for V */ + retval = drbg_hash (drbg, &cipherin); + memcpy(drbg->V, retval, drbg_blocklen (drbg)); + + /* 10.1.2.2 step 3 */ + if (!seed || 0 == seed->len) + return ret; + } + return 0; +} + +/* generate function of HMAC DRBG as defined in 10.1.2.5 */ +static gpg_err_code_t +drbg_hmac_generate (drbg_state_t drbg, unsigned char *buf, unsigned int buflen, + drbg_string_t *addtl) +{ + gpg_err_code_t ret = 0; + unsigned int len = 0; + drbg_string_t data; + + /* 10.1.2.5 step 2 */ + if (addtl && 0 < addtl->len) + { + addtl->next = NULL; + ret = drbg_hmac_update (drbg, addtl, 1); + if (ret) + return ret; + } + + drbg_string_fill (&data, drbg->V, drbg_statelen (drbg)); + while (len < buflen) + { + unsigned int outlen = 0; + /* 10.1.2.5 step 4.1 */ + byte *retval = drbg_hash (drbg, &data); + memcpy(drbg->V, retval, drbg_blocklen (drbg)); + outlen = (drbg_blocklen (drbg) < (buflen - len)) ? + drbg_blocklen (drbg) : (buflen - len); + + /* 10.1.2.5 step 4.2 */ + memcpy (buf + len, drbg->V, outlen); + len += outlen; + } + + /* 10.1.2.5 step 6 */ + if (addtl) + addtl->next = NULL; + ret = drbg_hmac_update (drbg, addtl, 1); + + return ret; +} + +static struct drbg_state_ops_s drbg_hmac_ops = { + drbg_hmac_update, + drbg_hmac_generate, + drbg_hmac_init, + drbg_hash_fini, +}; + +/****************************************************************** + * Hash DRBG callback functions + ******************************************************************/ + +/* + * scratchpad usage: as drbg_hash_update and drbg_hash_df are used + * interlinked, the scratchpad is used as follows: + * drbg_hash_update + * start: drbg->scratchpad + * length: drbg_statelen(drbg) + * drbg_hash_df: + * start: drbg->scratchpad + drbg_statelen(drbg) + * length: drbg_blocklen(drbg) + */ +/* Derivation Function for Hash DRBG as defined in 10.4.1 */ +static gpg_err_code_t +drbg_hash_df (drbg_state_t drbg, + unsigned char *outval, size_t outlen, + drbg_string_t *entropy) +{ + size_t len = 0; + unsigned char input[5]; + drbg_string_t data1; + + /* 10.4.1 step 3 */ + input[0] = 1; + buf_put_be32 (&input[1], (outlen * 8)); + + /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ + drbg_string_fill (&data1, input, 5); + data1.next = entropy; + + /* 10.4.1 step 4 */ + while (len < outlen) + { + short blocklen = 0; + /* 10.4.1 step 4.1 */ + byte *retval = drbg_hash (drbg, &data1); + /* 10.4.1 step 4.2 */ + input[0]++; + blocklen = (drbg_blocklen (drbg) < (outlen - len)) ? + drbg_blocklen (drbg) : (outlen - len); + memcpy (outval + len, retval, blocklen); + len += blocklen; + } + + return 0; +} + +/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */ +static gpg_err_code_t +drbg_hash_update (drbg_state_t drbg, drbg_string_t *seed, int reseed) +{ + gpg_err_code_t ret = 0; + drbg_string_t data1, data2; + unsigned char *V = drbg->scratchpad; + unsigned char prefix = DRBG_PREFIX1; + + memset (drbg->scratchpad, 0, drbg_statelen (drbg)); + if (!seed) + return GPG_ERR_INV_ARG; + + if (reseed) + { + /* 10.1.1.3 step 1: string length is concatenation of + * 1 byte, V and seed (which is concatenated entropy/addtl + * input) + */ + memcpy (V, drbg->V, drbg_statelen (drbg)); + drbg_string_fill (&data1, &prefix, 1); + drbg_string_fill (&data2, V, drbg_statelen (drbg)); + data1.next = &data2; + data2.next = seed; + } + else + { + drbg_string_fill (&data1, seed->buf, seed->len); + data1.next = seed->next; + } + + /* 10.1.1.2 / 10.1.1.3 step 2 and 3 */ + ret = drbg_hash_df (drbg, drbg->V, drbg_statelen (drbg), &data1); + if (ret) + goto out; + + /* 10.1.1.2 / 10.1.1.3 step 4 -- concatenation */ + prefix = DRBG_PREFIX0; + drbg_string_fill (&data1, &prefix, 1); + drbg_string_fill (&data2, drbg->V, drbg_statelen (drbg)); + data1.next = &data2; + /* 10.1.1.2 / 10.1.1.3 step 4 -- df operation */ + ret = drbg_hash_df (drbg, drbg->C, drbg_statelen (drbg), &data1); + + out: + memset (drbg->scratchpad, 0, drbg_statelen (drbg)); + return ret; +} + +/* Processing of additional information string for Hash DRBG. */ +static gpg_err_code_t +drbg_hash_process_addtl (drbg_state_t drbg, drbg_string_t *addtl) +{ + drbg_string_t data1, data2; + drbg_string_t *data3; + unsigned char prefix = DRBG_PREFIX2; + byte *retval; + + /* 10.1.1.4 step 2 */ + if (!addtl || 0 == addtl->len) + return 0; + + /* 10.1.1.4 step 2a -- concatenation */ + drbg_string_fill (&data1, &prefix, 1); + drbg_string_fill (&data2, drbg->V, drbg_statelen (drbg)); + data3 = addtl; + data1.next = &data2; + data2.next = data3; + data3->next = NULL; + /* 10.1.1.4 step 2a -- cipher invocation */ + retval = drbg_hash (drbg, &data1); + + /* 10.1.1.4 step 2b */ + drbg_add_buf (drbg->V, drbg_statelen (drbg), retval, drbg_blocklen (drbg)); + + return 0; +} + +/* + * Hashgen defined in 10.1.1.4 + */ +static gpg_err_code_t +drbg_hash_hashgen (drbg_state_t drbg, unsigned char *buf, unsigned int buflen) +{ + unsigned int len = 0; + unsigned char *src = drbg->scratchpad; + drbg_string_t data; + unsigned char prefix = DRBG_PREFIX1; + + /* 10.1.1.4 step hashgen 2 */ + memcpy (src, drbg->V, drbg_statelen (drbg)); + + drbg_string_fill (&data, src, drbg_statelen (drbg)); + while (len < buflen) + { + unsigned int outlen = 0; + /* 10.1.1.4 step hashgen 4.1 */ + byte *retval = drbg_hash (drbg, &data); + outlen = (drbg_blocklen (drbg) < (buflen - len)) ? + drbg_blocklen (drbg) : (buflen - len); + /* 10.1.1.4 step hashgen 4.2 */ + memcpy (buf + len, retval, outlen); + len += outlen; + /* 10.1.1.4 hashgen step 4.3 */ + if (len < buflen) + drbg_add_buf (src, drbg_statelen (drbg), &prefix, 1); + } + + memset (drbg->scratchpad, 0, drbg_statelen (drbg)); + return 0; +} + +/* Generate function for Hash DRBG as defined in 10.1.1.4 */ +static gpg_err_code_t +drbg_hash_generate (drbg_state_t drbg, unsigned char *buf, unsigned int buflen, + drbg_string_t *addtl) +{ + gpg_err_code_t ret; + unsigned char prefix = DRBG_PREFIX3; + drbg_string_t data1, data2; + byte *retval; + union + { + unsigned char req[8]; + u64 req_int; + } u; + + /* 10.1.1.4 step 2 */ + ret = drbg_hash_process_addtl (drbg, addtl); + if (ret) + return ret; + /* 10.1.1.4 step 3 -- invocation of the Hashgen function defined in + * 10.1.1.4 */ + ret = drbg_hash_hashgen (drbg, buf, buflen); + if (ret) + return ret; + + /* 10.1.1.4 step 4 */ + drbg_string_fill (&data1, &prefix, 1); + drbg_string_fill (&data2, drbg->V, drbg_statelen (drbg)); + data1.next = &data2; + + /* this is the value H as documented in 10.1.1.4 */ + retval = drbg_hash (drbg, &data1); + + /* 10.1.1.4 step 5 */ + drbg_add_buf (drbg->V, drbg_statelen (drbg), retval, drbg_blocklen (drbg)); + drbg_add_buf (drbg->V, drbg_statelen (drbg), drbg->C, drbg_statelen (drbg)); + u.req_int = be_bswap64 (drbg->reseed_ctr); + drbg_add_buf (drbg->V, drbg_statelen (drbg), u.req, sizeof (u.req)); + + return ret; +} + +/* + * scratchpad usage: as update and generate are used isolated, both + * can use the scratchpad + */ +static struct drbg_state_ops_s drbg_hash_ops = { + drbg_hash_update, + drbg_hash_generate, + drbg_hash_init, + drbg_hash_fini, +}; + +/****************************************************************** + * Functions common for DRBG implementations + ******************************************************************/ + +/* + * Seeding or reseeding of the DRBG + * + * @drbg: DRBG state struct + * @pers: personalization / additional information buffer + * @reseed: 0 for initial seed process, 1 for reseeding + * + * return: + * 0 on success + * error value otherwise + */ +static gpg_err_code_t +drbg_seed (drbg_state_t drbg, drbg_string_t *pers, int reseed) +{ + gpg_err_code_t ret = 0; + unsigned char *entropy = NULL; + size_t entropylen = 0; + drbg_string_t data1; + + /* 9.1 / 9.2 / 9.3.1 step 3 */ + if (pers && pers->len > (drbg_max_addtl ())) + { + dbg (("DRBG: personalization string too long %lu\n", pers->len)); + return GPG_ERR_INV_ARG; + } + if (drbg->test_data && drbg->test_data->testentropy) + { + drbg_string_fill (&data1, drbg->test_data->testentropy->buf, + drbg->test_data->testentropy->len); + dbg (("DRBG: using test entropy\n")); + } + else + { + /* Gather entropy equal to the security strength of the DRBG. + * With a derivation function, a nonce is required in addition + * to the entropy. A nonce must be at least 1/2 of the security + * strength of the DRBG in size. Thus, entropy * nonce is 3/2 + * of the strength. The consideration of a nonce is only + * applicable during initial seeding. */ + entropylen = drbg_sec_strength (drbg->core->flags); + if (!entropylen) + return GPG_ERR_GENERAL; + if (0 == reseed) + /* make sure we round up strength/2 in + * case it is not divisible by 2 */ + entropylen = ((entropylen + 1) / 2) * 3; + dbg (("DRBG: (re)seeding with %lu bytes of entropy\n", entropylen)); + entropy = xcalloc_secure (1, entropylen); + if (!entropy) + return GPG_ERR_ENOMEM; + ret = drbg_get_entropy (drbg, entropy, entropylen); + if (ret) + goto out; + drbg_string_fill (&data1, entropy, entropylen); + } + + /* concatenation of entropy with personalization str / addtl input) + * the variable pers is directly handed by the caller, check its + * contents whether it is appropriate */ + if (pers && pers->buf && 0 < pers->len && NULL == pers->next) + { + data1.next = pers; + dbg (("DRBG: using personalization string\n")); + } + + ret = drbg->d_ops->update (drbg, &data1, reseed); + dbg (("DRBG: state updated with seed\n")); + if (ret) + goto out; + drbg->seeded = 1; + /* 10.1.1.2 / 10.1.1.3 step 5 */ + drbg->reseed_ctr = 1; + + out: + xfree (entropy); + return ret; +} + + +/************************************************************************* + * Exported interfaces. + *************************************************************************/ + +/* + * DRBG generate function as required by SP800-90A - this function + * generates random numbers + * + * @drbg DRBG state handle + * @buf Buffer where to store the random numbers -- the buffer must already + * be pre-allocated by caller + * @buflen Length of output buffer - this value defines the number of random + * bytes pulled from DRBG + * @addtl Additional input that is mixed into state, may be NULL -- note + * the entropy is pulled by the DRBG internally unconditionally + * as defined in SP800-90A. The additional input is mixed into + * the state in addition to the pulled entropy. + * + * return: Generated number of bytes. + */ +static gpg_err_code_t +drbg_generate (drbg_state_t drbg, + unsigned char *buf, unsigned int buflen, + drbg_string_t *addtl) +{ + gpg_err_code_t ret = GPG_ERR_INV_ARG; + + if (0 == buflen || !buf) + { + dbg (("DRBG: no buffer provided\n")); + return ret; + } + if (addtl && NULL == addtl->buf && 0 < addtl->len) + { + dbg (("DRBG: wrong format of additional information\n")); + return ret; + } + + /* 9.3.1 step 2 */ + if (buflen > (drbg_max_request_bytes ())) + { + dbg (("DRBG: requested random numbers too large %u\n", buflen)); + return ret; + } + /* 9.3.1 step 3 is implicit with the chosen DRBG */ + /* 9.3.1 step 4 */ + if (addtl && addtl->len > (drbg_max_addtl ())) + { + dbg (("DRBG: additional information string too long %lu\n", + addtl->len)); + return ret; + } + /* 9.3.1 step 5 is implicit with the chosen DRBG */ + /* 9.3.1 step 6 and 9 supplemented by 9.3.2 step c -- the spec is a + * bit convoluted here, we make it simpler */ + if ((drbg_max_requests ()) < drbg->reseed_ctr) + drbg->seeded = 0; + + if (drbg->pr || !drbg->seeded) + { + dbg (("DRBG: reseeding before generation (prediction resistance: %s, state %s)\n", drbg->pr ? "true" : "false", drbg->seeded ? "seeded" : "unseeded")); + /* 9.3.1 steps 7.1 through 7.3 */ + ret = drbg_seed (drbg, addtl, 1); + if (ret) + return ret; + /* 9.3.1 step 7.4 */ + addtl = NULL; + } + + if (addtl && addtl->buf) + { + dbg (("DRBG: using additional information string\n")); + } + + /* 9.3.1 step 8 and 10 */ + ret = drbg->d_ops->generate (drbg, buf, buflen, addtl); + + /* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */ + drbg->reseed_ctr++; + if (ret) + return ret; + + /* 11.3.3 -- re-perform self tests after some generated random + * numbers, the chosen value after which self test is performed + * is arbitrary, but it should be reasonable */ + /* Here we do not perform the self tests because of the following + * reasons: it is mathematically impossible that the initial self tests + * were successfully and the following are not. If the initial would + * pass and the following would not, the system integrity is violated. + * In this case, the entire system operation is questionable and it + * is unlikely that the integrity violation only affects to the + * correct operation of the DRBG. + */ +#if 0 + if (drbg->reseed_ctr && !(drbg->reseed_ctr % 4096)) + { + dbg (("DRBG: start to perform self test\n")); + ret = drbg_healthcheck (); + if (ret) + { + log_fatal (("DRBG: self test failed\n")); + return ret; + } + else + { + dbg (("DRBG: self test successful\n")); + } + } +#endif + + return ret; +} + +/* + * Wrapper around drbg_generate which can pull arbitrary long strings + * from the DRBG without hitting the maximum request limitation. + * + * Parameters: see drbg_generate + * Return codes: see drbg_generate -- if one drbg_generate request fails, + * the entire drbg_generate_long request fails + */ +static gpg_err_code_t +drbg_generate_long (drbg_state_t drbg, + unsigned char *buf, unsigned int buflen, + drbg_string_t *addtl) +{ + gpg_err_code_t ret = 0; + unsigned int slice = 0; + unsigned char *buf_p = buf; + unsigned len = 0; + do + { + unsigned int chunk = 0; + slice = ((buflen - len) / drbg_max_request_bytes ()); + chunk = slice ? drbg_max_request_bytes () : (buflen - len); + ret = drbg_generate (drbg, buf_p, chunk, addtl); + if (ret) + return ret; + buf_p += chunk; + len += chunk; + } + while (slice > 0 && (len < buflen)); + return ret; +} + +/* + * DRBG uninstantiate function as required by SP800-90A - this function + * frees all buffers and the DRBG handle + * + * @drbg DRBG state handle + * + * return + * 0 on success + */ +static gpg_err_code_t +drbg_uninstantiate (drbg_state_t drbg) +{ + if (!drbg) + return GPG_ERR_INV_ARG; + drbg->d_ops->crypto_fini(drbg); + xfree (drbg->V); + drbg->V = NULL; + xfree (drbg->C); + drbg->C = NULL; + drbg->reseed_ctr = 0; + xfree (drbg->scratchpad); + drbg->scratchpad = NULL; + drbg->seeded = 0; + drbg->pr = 0; + drbg->seed_init_pid = 0; + return 0; +} + +/* + * DRBG instantiation function as required by SP800-90A - this function + * sets up the DRBG handle, performs the initial seeding and all sanity + * checks required by SP800-90A + * + * @drbg memory of state -- if NULL, new memory is allocated + * @pers Personalization string that is mixed into state, may be NULL -- note + * the entropy is pulled by the DRBG internally unconditionally + * as defined in SP800-90A. The additional input is mixed into + * the state in addition to the pulled entropy. + * @coreref reference to core + * @flags Flags defining the requested DRBG type and cipher type. The flags + * are defined in drbg.h and may be XORed. Beware, if you XOR multiple + * cipher types together, the code picks the core on a first come first + * serve basis as it iterates through the available cipher cores and + * uses the one with the first match. The minimum required flags are: + * cipher type flag + * + * return + * 0 on success + * error value otherwise + */ +static gpg_err_code_t +drbg_instantiate (drbg_state_t drbg, + drbg_string_t *pers, int coreref, int pr) +{ + gpg_err_code_t ret = GPG_ERR_ENOMEM; + unsigned int sb_size = 0; + + if (!drbg) + return GPG_ERR_INV_ARG; + + dbg (("DRBG: Initializing DRBG core %d with prediction resistance %s\n", + coreref, pr ? "enabled" : "disabled")); + drbg->core = &drbg_cores[coreref]; + drbg->pr = pr; + drbg->seeded = 0; + if (drbg->core->flags & DRBG_HMAC) + drbg->d_ops = &drbg_hmac_ops; + else if (drbg->core->flags & DRBG_HASH_MASK) + drbg->d_ops = &drbg_hash_ops; + else if (drbg->core->flags & DRBG_CTR_MASK) + drbg->d_ops = &drbg_ctr_ops; + else + return GPG_ERR_GENERAL; + /* 9.1 step 1 is implicit with the selected DRBG type -- see + * drbg_sec_strength() */ + + /* 9.1 step 2 is implicit as caller can select prediction resistance + * and the flag is copied into drbg->flags -- + * all DRBG types support prediction resistance */ + + /* 9.1 step 4 is implicit in drbg_sec_strength */ + + ret = drbg->d_ops->crypto_init(drbg); + if (ret) + goto err; + + drbg->V = xcalloc_secure (1, drbg_statelen (drbg)); + if (!drbg->V) + goto fini; + drbg->C = xcalloc_secure (1, drbg_statelen (drbg)); + if (!drbg->C) + goto fini; + /* scratchpad is only generated for CTR and Hash */ + if (drbg->core->flags & DRBG_HMAC) + sb_size = 0; + else if (drbg->core->flags & DRBG_CTR_MASK) + sb_size = drbg_statelen (drbg) + drbg_blocklen (drbg) + /* temp */ + drbg_statelen (drbg) + /* df_data */ + drbg_blocklen (drbg) + /* pad */ + drbg_blocklen (drbg) + /* iv */ + drbg_statelen (drbg) + drbg_blocklen (drbg); /* temp */ + else + sb_size = drbg_statelen (drbg); + + if (0 < sb_size) + { + drbg->scratchpad = xcalloc_secure (1, sb_size); + if (!drbg->scratchpad) + goto fini; + } + dbg (("DRBG: state allocated with scratchpad size %u bytes\n", sb_size)); + + /* 9.1 step 6 through 11 */ + ret = drbg_seed (drbg, pers, 0); + if (ret) + goto fini; + + dbg (("DRBG: core %d %s prediction resistance successfully initialized\n", + coreref, pr ? "with" : "without")); + return 0; + + fini: + drbg->d_ops->crypto_fini(drbg); + err: + drbg_uninstantiate (drbg); + return ret; +} + +/* + * DRBG reseed function as required by SP800-90A + * + * @drbg DRBG state handle + * @addtl Additional input that is mixed into state, may be NULL -- note + * the entropy is pulled by the DRBG internally unconditionally + * as defined in SP800-90A. The additional input is mixed into + * the state in addition to the pulled entropy. + * + * return + * 0 on success + * error value otherwise + */ +static gpg_err_code_t +drbg_reseed (drbg_state_t drbg,drbg_string_t *addtl) +{ + gpg_err_code_t ret = 0; + ret = drbg_seed (drbg, addtl, 1); + return ret; +} + + + +/****************************************************************** + * Libgcrypt integration code. + ******************************************************************/ + +/*************************************************** + * Libgcrypt backend functions to the RNG API code. + ***************************************************/ + +static inline void +drbg_lock (void) +{ + gpg_err_code_t ec; + + ec = gpgrt_lock_lock (&drbg_lock_var); + if (ec) + log_fatal ("failed to acquire the RNG lock: %s\n", gpg_strerror (ec)); +} + +static inline void +drbg_unlock (void) +{ + gpg_err_code_t ec; + + ec = gpgrt_lock_unlock (&drbg_lock_var); + if (ec) + log_fatal ("failed to release the RNG lock: %s\n", gpg_strerror (ec)); +} + +/* Basic initialization is required to initialize mutexes and + do a few checks on the implementation. */ +static void +basic_initialization (void) +{ + static int initialized; + + if (initialized) + return; + initialized = 1; + + /* Make sure that we are still using the values we have + traditionally used for the random levels. */ + gcry_assert (GCRY_WEAK_RANDOM == 0 + && GCRY_STRONG_RANDOM == 1 + && GCRY_VERY_STRONG_RANDOM == 2); +} + +/****** helper functions where lock must be held by caller *****/ + +/* Check whether given flags are known to point to an applicable DRBG */ +static gpg_err_code_t +drbg_algo_available (u32 flags, int *coreref) +{ + int i = 0; + for (i = 0; ARRAY_SIZE (drbg_cores) > i; i++) + { + if ((drbg_cores[i].flags & DRBG_CIPHER_MASK) == + (flags & DRBG_CIPHER_MASK)) + { + *coreref = i; + return 0; + } + } + return GPG_ERR_GENERAL; +} + +static gpg_err_code_t +_drbg_init_internal (u32 flags, drbg_string_t *pers) +{ + static u32 oldflags; + gpg_err_code_t ret = 0; + int coreref = 0; + int pr = 0; + + /* If a caller provides 0 as flags, use the flags of the previous + * initialization, otherwise use the current flags and remember them + * for the next invocation. If no flag is given and no global state + * is set this is the first initialization and we set the default + * type. + */ + if (!flags && !drbg_state) + flags = oldflags = DRBG_DEFAULT_TYPE; + else if (!flags) + flags = oldflags; + else + oldflags = flags; + + ret = drbg_algo_available (flags, &coreref); + if (ret) + return ret; + + if (drbg_state) + { + drbg_uninstantiate (drbg_state); + } + else + { + drbg_state = xtrycalloc_secure (1, sizeof *drbg_state); + if (!drbg_state) + return gpg_err_code_from_syserror (); + } + if (flags & DRBG_PREDICTION_RESIST) + pr = 1; + ret = drbg_instantiate (drbg_state, pers, coreref, pr); + if (ret) + fips_signal_error ("DRBG cannot be initialized"); + else + drbg_state->seed_init_pid = getpid (); + return ret; +} + +/************* calls available to common RNG code **************/ + +/* + * Initialize one DRBG invoked by the libgcrypt API + */ +void +_gcry_rngdrbg_inititialize (int full) +{ + basic_initialization (); + if (!full) + return; + drbg_lock (); + if (!drbg_state) + _drbg_init_internal (0, NULL); + drbg_unlock (); +} + +/* + * Backend handler function for GCRYCTL_DRBG_REINIT + * + * Select a different DRBG type and initialize it. + * Function checks whether requested DRBG type exists and returns an error in + * case it does not. In case of an error, the previous instantiated DRBG is + * left untouched and alive. Thus, in case of an error, a DRBG is always + * available, even if it is not the chosen one. + * + * Re-initialization will be performed in any case regardless whether flags + * or personalization string are set. + * + * If flags is NULL, do not change current DRBG. If PERS is NULL and + * NPERS is 0, re-initialize without personalization string. If PERS + * is not NULL NPERS must be one and PERS and the first ietm from the + * bufer is take as personalization string. + */ +gpg_err_code_t +_gcry_rngdrbg_reinit (const char *flagstr, gcry_buffer_t *pers, int npers) +{ + gpg_err_code_t ret; + unsigned int flags; + + /* If PERS is not given we expect NPERS to be zero; if given we + expect a one-item array. */ + if ((!pers && npers) || (pers && npers != 1)) + return GPG_ERR_INV_ARG; + + ret = parse_flag_string (flagstr, &flags); + if (!ret) + { + dbg (("DRBG: reinitialize internal DRBG state with flags %u\n", flags)); + drbg_lock (); + if (pers) + { + drbg_string_t persbuf; + + drbg_string_fill + (&persbuf, (const unsigned char *)pers[0].data + pers[0].off, + pers[0].len); + ret = _drbg_init_internal (flags, &persbuf); + } + else + ret = _drbg_init_internal (flags, NULL); + drbg_unlock (); + } + return ret; +} + +/* Try to close the FDs of the random gather module. This is + * currently only implemented for rndlinux. */ +void +_gcry_rngdrbg_close_fds (void) +{ +#if USE_RNDLINUX + drbg_lock (); + _gcry_rndlinux_gather_random (NULL, 0, 0, 0); + drbg_unlock (); +#endif +} + +/* Print some statistics about the RNG. */ +void +_gcry_rngdrbg_dump_stats (void) +{ + /* Not yet implemented. */ + /* Maybe dumping of reseed counter? */ +} + +/* This function returns true if no real RNG is available or the + * quality of the RNG has been degraded for test purposes. */ +int +_gcry_rngdrbg_is_faked (void) +{ + return 0; /* Faked random is not allowed. */ +} + +/* 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. */ +gcry_error_t +_gcry_rngdrbg_add_bytes (const void *buf, size_t buflen, int quality) +{ + gpg_err_code_t ret = 0; + drbg_string_t seed; + (void) quality; + _gcry_rngdrbg_inititialize (1); /* Auto-initialize if needed */ + if (!drbg_state) + return GPG_ERR_GENERAL; + drbg_string_fill (&seed, (unsigned char *) buf, buflen); + drbg_lock (); + ret = drbg_reseed (drbg_state, &seed); + drbg_unlock (); + return ret; +} + +/* This function is to be used for all types of random numbers, including + * nonces + */ +void +_gcry_rngdrbg_randomize (void *buffer, size_t length, + enum gcry_random_level level) +{ + (void) level; + _gcry_rngdrbg_inititialize (1); /* Auto-initialize if needed */ + drbg_lock (); + if (!drbg_state) + { + fips_signal_error ("DRBG is not initialized"); + goto bailout; + } + + /* As reseeding changes the entire state of the DRBG, including any + * key, either a re-init or a reseed is sufficient for a fork */ + if (drbg_state->seed_init_pid != getpid ()) + { + /* We are in a child of us. Perform a reseeding. */ + if (drbg_reseed (drbg_state, NULL)) + { + fips_signal_error ("reseeding upon fork failed"); + log_fatal ("severe error getting random\n"); + goto bailout; + } + } + /* potential integer overflow is covered by drbg_generate which + * ensures that length cannot overflow an unsigned int */ + if (0 < length) + { + if (!buffer) + goto bailout; + if (drbg_generate_long (drbg_state, buffer, (unsigned int) length, NULL)) + log_fatal ("No random numbers generated\n"); + } + else + { + drbg_gen_t *data = (drbg_gen_t *)buffer; + /* catch NULL pointer */ + if (!data || !data->outbuf) + { + fips_signal_error ("No output buffer provided"); + goto bailout; + } + if (drbg_generate_long (drbg_state, data->outbuf, data->outlen, + data->addtl)) + log_fatal ("No random numbers generated\n"); + } + + bailout: + drbg_unlock (); + return; + +} + +/*************************************************************** + * Self-test code + ***************************************************************/ + +/* + * Test vectors from + * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip + */ +struct gcry_drbg_test_vector drbg_test_pr[] = { + { + /* .flags = */ "sha256 pr" /* DRBG_PR_HASHSHA256 */, + /* .entropy = */ (unsigned char *) + "\x5d\xf2\x14\xbc\xf6\xb5\x4e\x0b\xf0\x0d\x6f\x2d" + "\xe2\x01\x66\x7b\xd0\xa4\x73\xa4\x21\xdd\xb0\xc0" + "\x51\x79\x09\xf4\xea\xa9\x08\xfa\xa6\x67\xe0\xe1" + "\xd1\x88\xa8\xad\xee\x69\x74\xb3\x55\x06\x9b\xf6", + /* .entropylen = */ 48, + /* .entpra = */ (unsigned char *) + "\xef\x48\x06\xa2\xc2\x45\xf1\x44\xfa\x34\x2c\xeb" + "\x8d\x78\x3c\x09\x8f\x34\x72\x20\xf2\xe7\xfd\x13" + "\x76\x0a\xf6\xdc\x3c\xf5\xc0\x15", + /* .entprb = */ (unsigned char *) + "\x4b\xbe\xe5\x24\xed\x6a\x2d\x0c\xdb\x73\x5e\x09" + "\xf9\xad\x67\x7c\x51\x47\x8b\x6b\x30\x2a\xc6\xde" + "\x76\xaa\x55\x04\x8b\x0a\x72\x95", + /* .entprlen = */ 32, + /* .addtla = */ (unsigned char *) + "\xbe\x13\xdb\x2a\xe9\xa8\xfe\x09\x97\xe1\xce\x5d" + "\xe8\xbb\xc0\x7c\x4f\xcb\x62\x19\x3f\x0f\xd2\xad" + "\xa9\xd0\x1d\x59\x02\xc4\xff\x70", + /* .addtlb = */ (unsigned char *) + "\x6f\x96\x13\xe2\xa7\xf5\x6c\xfe\xdf\x66\xe3\x31" + "\x63\x76\xbf\x20\x27\x06\x49\xf1\xf3\x01\x77\x41" + "\x9f\xeb\xe4\x38\xfe\x67\x00\xcd", + /* .addtllen = */ 32, + /* .pers = */ NULL, + /* .perslen = */ 0, + /* .expected = */ (unsigned char *) + "\x3b\x14\x71\x99\xa1\xda\xa0\x42\xe6\xc8\x85\x32" + "\x70\x20\x32\x53\x9a\xbe\xd1\x1e\x15\xef\xfb\x4c" + "\x25\x6e\x19\x3a\xf0\xb9\xcb\xde\xf0\x3b\xc6\x18" + "\x4d\x85\x5a\x9b\xf1\xe3\xc2\x23\x03\x93\x08\xdb" + "\xa7\x07\x4b\x33\x78\x40\x4d\xeb\x24\xf5\x6e\x81" + "\x4a\x1b\x6e\xa3\x94\x52\x43\xb0\xaf\x2e\x21\xf4" + "\x42\x46\x8e\x90\xed\x34\x21\x75\xea\xda\x67\xb6" + "\xe4\xf6\xff\xc6\x31\x6c\x9a\x5a\xdb\xb3\x97\x13" + "\x09\xd3\x20\x98\x33\x2d\x6d\xd7\xb5\x6a\xa8\xa9" + "\x9a\x5b\xd6\x87\x52\xa1\x89\x2b\x4b\x9c\x64\x60" + "\x50\x47\xa3\x63\x81\x16\xaf\x19", + /* .expectedlen = */ 128, + /* .entropyreseed = */ NULL, + /* .entropyreseed_len = */ 0, + /* .addtl_reseed = */ NULL, + /* .addtl_reseed_len = */ 0 + }, + { + /* flags = */ "hmac sha256 pr" /* DRBG_PR_HMACSHA256 */, + /* .entropy = */ (unsigned char *) + "\x13\x54\x96\xfc\x1b\x7d\x28\xf3\x18\xc9\xa7\x89" + "\xb6\xb3\xc8\x72\xac\x00\xd4\x59\x36\x25\x05\xaf" + "\xa5\xdb\x96\xcb\x3c\x58\x46\x87\xa5\xaa\xbf\x20" + "\x3b\xfe\x23\x0e\xd1\xc7\x41\x0f\x3f\xc9\xb3\x67", + /* .entropylen = */ 48, + /* .entpra = */ (unsigned char *) + "\xe2\xbd\xb7\x48\x08\x06\xf3\xe1\x93\x3c\xac\x79" + "\xa7\x2b\x11\xda\xe3\x2e\xe1\x91\xa5\x02\x19\x57" + "\x20\x28\xad\xf2\x60\xd7\xcd\x45", + /* .entprb = */ (unsigned char *) + "\x8b\xd4\x69\xfc\xff\x59\x95\x95\xc6\x51\xde\x71" + "\x68\x5f\xfc\xf9\x4a\xab\xec\x5a\xcb\xbe\xd3\x66" + "\x1f\xfa\x74\xd3\xac\xa6\x74\x60", + /* .entprlen = */ 32, + /* .addtla = */ NULL, + /* .addtlb = */ NULL, + /* .addtllen = */ 0, + /* .pers = */ (unsigned char *) + "\x64\xb6\xfc\x60\xbc\x61\x76\x23\x6d\x3f\x4a\x0f" + "\xe1\xb4\xd5\x20\x9e\x70\xdd\x03\x53\x6d\xbf\xce" + "\xcd\x56\x80\xbc\xb8\x15\xc8\xaa", + /* .perslen = */ 32, + /* .expected = */ (unsigned char *) + "\x1f\x9e\xaf\xe4\xd2\x46\xb7\x47\x41\x4c\x65\x99" + "\x01\xe9\x3b\xbb\x83\x0c\x0a\xb0\xc1\x3a\xe2\xb3" + "\x31\x4e\xeb\x93\x73\xee\x0b\x26\xc2\x63\xa5\x75" + "\x45\x99\xd4\x5c\x9f\xa1\xd4\x45\x87\x6b\x20\x61" + "\x40\xea\x78\xa5\x32\xdf\x9e\x66\x17\xaf\xb1\x88" + "\x9e\x2e\x23\xdd\xc1\xda\x13\x97\x88\xa5\xb6\x5e" + "\x90\x14\x4e\xef\x13\xab\x5c\xd9\x2c\x97\x9e\x7c" + "\xd7\xf8\xce\xea\x81\xf5\xcd\x71\x15\x49\x44\xce" + "\x83\xb6\x05\xfb\x7d\x30\xb5\x57\x2c\x31\x4f\xfc" + "\xfe\x80\xb6\xc0\x13\x0c\x5b\x9b\x2e\x8f\x3d\xfc" + "\xc2\xa3\x0c\x11\x1b\x80\x5f\xf3", + /* .expectedlen = */ 128, + /* .entropyreseed = */ NULL, + /* .entropyreseed_len = */ 0, + /* .addtl_reseed = */ NULL, + /* .addtl_reseed_len = */ 0 + }, + { + /* .flags = */ "aes sym128 pr", /* DRBG_PR_CTRAES128 */ + /* .entropy = */ (unsigned char *) + "\x92\x89\x8f\x31\xfa\x1c\xff\x6d\x18\x2f\x26\x06" + "\x43\xdf\xf8\x18\xc2\xa4\xd9\x72\xc3\xb9\xb6\x97", + /* .entropylen = */ 24, + /* .entpra = */ (unsigned char *) + "\x20\x72\x8a\x06\xf8\x6f\x8d\xd4\x41\xe2\x72\xb7" + "\xc4\x2c\xe8\x10", + /* .entprb = */ (unsigned char *) + "\x3d\xb0\xf0\x94\xf3\x05\x50\x33\x17\x86\x3e\x22" + "\x08\xf7\xa5\x01", + /* .entprlen = */ 16, + /* .addtla = */ (unsigned char *) + "\x1a\x40\xfa\xe3\xcc\x6c\x7c\xa0\xf8\xda\xba\x59" + "\x23\x6d\xad\x1d", + /* .addtlb = */ (unsigned char *) + "\x9f\x72\x76\x6c\xc7\x46\xe5\xed\x2e\x53\x20\x12" + "\xbc\x59\x31\x8c", + /* .addtllen = */ 16, + /* .pers = */ (unsigned char *) + "\xea\x65\xee\x60\x26\x4e\x7e\xb6\x0e\x82\x68\xc4" + "\x37\x3c\x5c\x0b", + /* .perslen = */ 16, + /* .expected = */ (unsigned char *) + "\x5a\x35\x39\x87\x0f\x4d\x22\xa4\x09\x24\xee\x71" + "\xc9\x6f\xac\x72\x0a\xd6\xf0\x88\x82\xd0\x83\x28" + "\x73\xec\x3f\x93\xd8\xab\x45\x23\xf0\x7e\xac\x45" + "\x14\x5e\x93\x9f\xb1\xd6\x76\x43\x3d\xb6\xe8\x08" + "\x88\xf6\xda\x89\x08\x77\x42\xfe\x1a\xf4\x3f\xc4" + "\x23\xc5\x1f\x68", + /* .expectedlen = */ 64, + /* .entropyreseed = */ NULL, + /* .entropyreseed_len = */ 0, + /* .addtl_reseed = */ NULL, + /* .addtl_reseed_len = */ 0 + } +}; + +struct gcry_drbg_test_vector drbg_test_nopr[] = { + { + /* .flags = */ "sha256" /* DRBG_NOPR_HASHSHA256 */, + /* .entropy = */ (unsigned char *) + "\x73\xd3\xfb\xa3\x94\x5f\x2b\x5f\xb9\x8f\xf6\x9c" + "\x8a\x93\x17\xae\x19\xc3\x4c\xc3\xd6\xca\xa3\x2d" + "\x16\xfc\x42\xd2\x2d\xd5\x6f\x56\xcc\x1d\x30\xff" + "\x9e\x06\x3e\x09\xce\x58\xe6\x9a\x35\xb3\xa6\x56", + /* .entropylen = */ 48, + /* .entpra = */ NULL, + /* .entprb = */ NULL, + /* .entprlen = */ 0, + /* .addtla = */ (unsigned char *) + "\xf4\xd5\x98\x3d\xa8\xfc\xfa\x37\xb7\x54\x67\x73" + "\xc7\xc3\xdd\x47\x34\x71\x02\x5d\xc1\xa0\xd3\x10" + "\xc1\x8b\xbd\xf5\x66\x34\x6f\xdd", + /* .addtlb = */ (unsigned char *) + "\xf7\x9e\x6a\x56\x0e\x73\xe9\xd9\x7a\xd1\x69\xe0" + "\x6f\x8c\x55\x1c\x44\xd1\xce\x6f\x28\xcc\xa4\x4d" + "\xa8\xc0\x85\xd1\x5a\x0c\x59\x40", + /* .addtllen = */ 32, + /* .pers = */ NULL, + /* .perslen = */ 0, + /* .expected = */ (unsigned char *) + "\x71\x7b\x93\x46\x1a\x40\xaa\x35\xa4\xaa\xc5\xe7" + "\x6d\x5b\x5b\x8a\xa0\xdf\x39\x7d\xae\x71\x58\x5b" + "\x3c\x7c\xb4\xf0\x89\xfa\x4a\x8c\xa9\x5c\x54\xc0" + "\x40\xdf\xbc\xce\x26\x81\x34\xf8\xba\x7d\x1c\xe8" + "\xad\x21\xe0\x74\xcf\x48\x84\x30\x1f\xa1\xd5\x4f" + "\x81\x42\x2f\xf4\xdb\x0b\x23\xf8\x73\x27\xb8\x1d" + "\x42\xf8\x44\x58\xd8\x5b\x29\x27\x0a\xf8\x69\x59" + "\xb5\x78\x44\xeb\x9e\xe0\x68\x6f\x42\x9a\xb0\x5b" + "\xe0\x4e\xcb\x6a\xaa\xe2\xd2\xd5\x33\x25\x3e\xe0" + "\x6c\xc7\x6a\x07\xa5\x03\x83\x9f\xe2\x8b\xd1\x1c" + "\x70\xa8\x07\x59\x97\xeb\xf6\xbe", + /* .expectedlen = */ 128, + /* .entropyreseed = */ NULL, + /* .entropyreseed_len = */ 0, + /* .addtl_reseed = */ NULL, + /* .addtl_reseed_len = */ 0 + }, + { + /* .flags = */ "hmac sha256" /* DRBG_NOPR_HMACSHA256 */, + /* .entropy = */ (unsigned char *) + "\x8d\xf0\x13\xb4\xd1\x03\x52\x30\x73\x91\x7d\xdf" + "\x6a\x86\x97\x93\x05\x9e\x99\x43\xfc\x86\x54\x54" + "\x9e\x7a\xb2\x2f\x7c\x29\xf1\x22\xda\x26\x25\xaf" + "\x2d\xdd\x4a\xbc\xce\x3c\xf4\xfa\x46\x59\xd8\x4e", + /* .entropylen = */ 48, + /* .entpra = */ NULL, + /* .entprb = */ NULL, + /* .entprlen = */ 0, + /* .addtla = */ NULL, + /* .addtlb = */ NULL, + /* .addtllen = */ 0, + /* .pers = */ (unsigned char *) + "\xb5\x71\xe6\x6d\x7c\x33\x8b\xc0\x7b\x76\xad\x37" + "\x57\xbb\x2f\x94\x52\xbf\x7e\x07\x43\x7a\xe8\x58" + "\x1c\xe7\xbc\x7c\x3a\xc6\x51\xa9", + /* .perslen = */ 32, + /* .expected = */ (unsigned char *) + "\xb9\x1c\xba\x4c\xc8\x4f\xa2\x5d\xf8\x61\x0b\x81" + "\xb6\x41\x40\x27\x68\xa2\x09\x72\x34\x93\x2e\x37" + "\xd5\x90\xb1\x15\x4c\xbd\x23\xf9\x74\x52\xe3\x10" + "\xe2\x91\xc4\x51\x46\x14\x7f\x0d\xa2\xd8\x17\x61" + "\xfe\x90\xfb\xa6\x4f\x94\x41\x9c\x0f\x66\x2b\x28" + "\xc1\xed\x94\xda\x48\x7b\xb7\xe7\x3e\xec\x79\x8f" + "\xbc\xf9\x81\xb7\x91\xd1\xbe\x4f\x17\x7a\x89\x07" + "\xaa\x3c\x40\x16\x43\xa5\xb6\x2b\x87\xb8\x9d\x66" + "\xb3\xa6\x0e\x40\xd4\xa8\xe4\xe9\xd8\x2a\xf6\xd2" + "\x70\x0e\x6f\x53\x5c\xdb\x51\xf7\x5c\x32\x17\x29" + "\x10\x37\x41\x03\x0c\xcc\x3a\x56", + /* .expectedlen = */ 128, + /* .entropyreseed = */ NULL, + /* .entropyreseed_len = */ 0, + /* .addtl_reseed = */ NULL, + /* .addtl_reseed_len = */ 0 + }, + { + /* .flags = */ "aes sym128" /* DRBG_NOPR_CTRAES128 */, + /* .entropy = */ (unsigned char *) + "\xc0\x70\x1f\x92\x50\x75\x8f\xcd\xf2\xbe\x73\x98" + "\x80\xdb\x66\xeb\x14\x68\xb4\xa5\x87\x9c\x2d\xa6", + /* .entropylen = */ 24, + /* .entpra = */ NULL, + /* .entprb = */ NULL, + /* .entprlen = */ 0, + /* .addtla = */ (unsigned char *) + "\xf9\x01\xf8\x16\x7a\x1d\xff\xde\x8e\x3c\x83\xe2" + "\x44\x85\xe7\xfe", + /* .addtlb = */ (unsigned char *) + "\x17\x1c\x09\x38\xc2\x38\x9f\x97\x87\x60\x55\xb4" + "\x82\x16\x62\x7f", + /* .addtllen = */ 16, + /* .pers = */ (unsigned char *) + "\x80\x08\xae\xe8\xe9\x69\x40\xc5\x08\x73\xc7\x9f" + "\x8e\xcf\xe0\x02", + /* .perslen = */ 16, + /* .expected = */ (unsigned char *) + "\x97\xc0\xc0\xe5\xa0\xcc\xf2\x4f\x33\x63\x48\x8a" + "\xdb\x13\x0a\x35\x89\xbf\x80\x65\x62\xee\x13\x95" + "\x7c\x33\xd3\x7d\xf4\x07\x77\x7a\x2b\x65\x0b\x5f" + "\x45\x5c\x13\xf1\x90\x77\x7f\xc5\x04\x3f\xcc\x1a" + "\x38\xf8\xcd\x1b\xbb\xd5\x57\xd1\x4a\x4c\x2e\x8a" + "\x2b\x49\x1e\x5c", + /* .expectedlen = */ 64, + /* .entropyreseed = */ NULL, + /* .entropyreseed_len = */ 0, + /* .addtl_reseed = */ NULL, + /* .addtl_reseed_len = */ 0 + }, + { + /* .flags = */ "sha1" /* DRBG_NOPR_HASHSHA1 */, + /* .entropy = */ (unsigned char *) + "\x16\x10\xb8\x28\xcc\xd2\x7d\xe0\x8c\xee\xa0\x32" + "\xa2\x0e\x92\x08\x49\x2c\xf1\x70\x92\x42\xf6\xb5", + /* .entropylen = */ 24, + /* .entpra = */ NULL, + /* .entprb = */ NULL, + /* .entprlen = */ 0, + /* .addtla = */ NULL, + /* .addtlb = */ NULL, + /* .addtllen = */ 0, + /* .pers = */ NULL, + /* .perslen = */ 0, + /* .expected = */ (unsigned char *) + "\x56\xf3\x3d\x4f\xdb\xb9\xa5\xb6\x4d\x26\x23\x44" + "\x97\xe9\xdc\xb8\x77\x98\xc6\x8d\x08\xf7\xc4\x11" + "\x99\xd4\xbd\xdf\x97\xeb\xbf\x6c\xb5\x55\x0e\x5d" + "\x14\x9f\xf4\xd5\xbd\x0f\x05\xf2\x5a\x69\x88\xc1" + "\x74\x36\x39\x62\x27\x18\x4a\xf8\x4a\x56\x43\x35" + "\x65\x8e\x2f\x85\x72\xbe\xa3\x33\xee\xe2\xab\xff" + "\x22\xff\xa6\xde\x3e\x22\xac\xa2", + /* .expectedlen = */ 80, + /* .entropyreseed = */ (unsigned char *) + "\x72\xd2\x8c\x90\x8e\xda\xf9\xa4\xd1\xe5\x26\xd8" + "\xf2\xde\xd5\x44", + /* .entropyreseed_len = */ 16, + /* .addtl_reseed = */ NULL, + /* .addtl_reseed_len = */ 0 + }, + { + /* .flags = */ "sha1" /* DRBG_NOPR_HASHSHA1 */, + /* .entropy = */ (unsigned char *) + "\xd9\xba\xb5\xce\xdc\xa9\x6f\x61\x78\xd6\x45\x09" + "\xa0\xdf\xdc\x5e\xda\xd8\x98\x94\x14\x45\x0e\x01", + /* .entropylen = */ 24, + /* .entpra = */ NULL, + /* .entprb = */ NULL, + /* .entprlen = */ 0, + /* .addtla = */ (unsigned char *) + "\x04\xfa\x28\x95\xaa\x5a\x6f\x8c\x57\x43\x34\x3b" + "\x80\x5e\x5e\xa4", + /* .addtlb = */ (unsigned char *) + "\xdf\x5d\xc4\x59\xdf\xf0\x2a\xa2\xf0\x52\xd7\x21" + "\xec\x60\x72\x30", + /* .addtllen = */ 16, + /* .pers = */ NULL, + /* .perslen = */ 0, + /* .expected = */ (unsigned char *) + "\xc4\x8b\x89\xf9\xda\x3f\x74\x82\x45\x55\x5d\x5d" + "\x03\x3b\x69\x3d\xd7\x1a\x4d\xf5\x69\x02\x05\xce" + "\xfc\xd7\x20\x11\x3c\xc2\x4e\x09\x89\x36\xff\x5e" + "\x77\xb5\x41\x53\x58\x70\xb3\x39\x46\x8c\xdd\x8d" + "\x6f\xaf\x8c\x56\x16\x3a\x70\x0a\x75\xb2\x3e\x59" + "\x9b\x5a\xec\xf1\x6f\x3b\xaf\x6d\x5f\x24\x19\x97" + "\x1f\x24\xf4\x46\x72\x0f\xea\xbe", + /* .expectedlen = */ 80, + /* .entropyreseed = */ (unsigned char *) + "\xc6\xba\xd0\x74\xc5\x90\x67\x86\xf5\xe1\xf3\x20" + "\x99\xf5\xb4\x91", + /* .entropyreseed_len = */ 16, + /* .addtl_reseed = */ (unsigned char *) + "\x3e\x6b\xf4\x6f\x4d\xaa\x38\x25\xd7\x19\x4e\x69" + "\x4e\x77\x52\xf7", + /* .addtl_reseed_len = */ 16 + } +}; + + +/* + * Tests implement the CAVS test approach as documented in + * http://csrc.nist.gov/groups/STM/cavp/documents/drbg/DRBGVS.pdf + */ + +/* + * CAVS test + * + * This function is not static as it is needed for as a private API + * call for the CAVS test tool. + */ +gpg_err_code_t +_gcry_rngdrbg_cavs_test (struct gcry_drbg_test_vector *test, unsigned char *buf) +{ + gpg_err_code_t ret = 0; + drbg_state_t drbg = NULL; + struct drbg_test_data_s test_data; + drbg_string_t addtl, pers, testentropy; + int coreref = 0; + int pr = 0; + u32 flags; + + ret = parse_flag_string (test->flagstr, &flags); + if (ret) + goto outbuf; + + ret = drbg_algo_available (flags, &coreref); + if (ret) + goto outbuf; + + drbg = xtrycalloc_secure (1, sizeof *drbg); + if (!drbg) + { + ret = gpg_err_code_from_syserror (); + goto outbuf; + } + + if ((flags & DRBG_PREDICTION_RESIST)) + pr = 1; + + test_data.testentropy = &testentropy; + drbg_string_fill (&testentropy, test->entropy, test->entropylen); + drbg->test_data = &test_data; + drbg_string_fill (&pers, test->pers, test->perslen); + ret = drbg_instantiate (drbg, &pers, coreref, pr); + if (ret) + goto outbuf; + + if (test->entropyreseed) + { + drbg_string_fill (&testentropy, test->entropyreseed, + test->entropyreseed_len); + drbg_string_fill (&addtl, test->addtl_reseed, + test->addtl_reseed_len); + if (drbg_reseed (drbg, &addtl)) + goto outbuf; + } + + drbg_string_fill (&addtl, test->addtla, test->addtllen); + if (test->entpra) + { + drbg_string_fill (&testentropy, test->entpra, test->entprlen); + drbg->test_data = &test_data; + } + drbg_generate_long (drbg, buf, test->expectedlen, &addtl); + + drbg_string_fill (&addtl, test->addtlb, test->addtllen); + if (test->entprb) + { + drbg_string_fill (&testentropy, test->entprb, test->entprlen); + drbg->test_data = &test_data; + } + drbg_generate_long (drbg, buf, test->expectedlen, &addtl); + drbg_uninstantiate (drbg); + + outbuf: + xfree (drbg); + return ret; +} + +/* + * Invoke the CAVS test and perform the final check whether the + * calculated random value matches the expected one. + * + * This function is not static as it is needed for as a private API + * call for the CAVS test tool. + */ +gpg_err_code_t +_gcry_rngdrbg_healthcheck_one (struct gcry_drbg_test_vector * test) +{ + gpg_err_code_t ret = GPG_ERR_ENOMEM; + unsigned char *buf = xcalloc_secure (1, test->expectedlen); + if (!buf) + return GPG_ERR_ENOMEM; + + ret = _gcry_rngdrbg_cavs_test (test, buf); + /* FIXME: The next line is wrong. */ + ret = memcmp (test->expected, buf, test->expectedlen); + + xfree (buf); + return ret; +} + +/* + * Tests as defined in 11.3.2 in addition to the cipher tests: testing + * of the error handling. + * + * Note, testing the reseed counter is not done as an automatic reseeding + * is performed in drbg_generate when the reseed counter is too large. + */ +static gpg_err_code_t +drbg_healthcheck_sanity (struct gcry_drbg_test_vector *test) +{ + unsigned int len = 0; + drbg_state_t drbg = NULL; + gpg_err_code_t ret = GPG_ERR_GENERAL; + gpg_err_code_t tmpret = GPG_ERR_GENERAL; + struct drbg_test_data_s test_data; + drbg_string_t addtl, testentropy; + int coreref = 0; + unsigned char *buf = NULL; + size_t max_addtllen, max_request_bytes; + u32 flags; + + /* only perform test in FIPS mode */ + if (0 == fips_mode ()) + return 0; + + ret = parse_flag_string (test->flagstr, &flags); + if (ret) + return ret; + ret = GPG_ERR_GENERAL; /* Fixme: Improve handling of RET. */ + + buf = xtrycalloc_secure (1, test->expectedlen); + if (!buf) + return gpg_err_code_from_syserror (); + tmpret = drbg_algo_available (flags, &coreref); + if (tmpret) + goto outbuf; + drbg = xtrycalloc_secure (1, sizeof *drbg); + if (!drbg) + { + ret = gpg_err_code_from_syserror (); + goto outbuf; + } + + /* if the following tests fail, it is likely that there is a buffer + * overflow and we get a SIGSEV */ + ret = drbg_instantiate (drbg, NULL, coreref, 1); + if (ret) + goto outbuf; + max_addtllen = drbg_max_addtl (); + max_request_bytes = drbg_max_request_bytes (); + /* overflow addtllen with additional info string */ + drbg_string_fill (&addtl, test->addtla, (max_addtllen + 1)); + len = drbg_generate (drbg, buf, test->expectedlen, &addtl); + if (len) + goto outdrbg; + + /* overflow max_bits */ + len = drbg_generate (drbg, buf, (max_request_bytes + 1), NULL); + if (len) + goto outdrbg; + drbg_uninstantiate (drbg); + + /* test failing entropy source as defined in 11.3.2 */ + test_data.testentropy = NULL; + test_data.fail_seed_source = 1; + drbg->test_data = &test_data; + tmpret = drbg_instantiate (drbg, NULL, coreref, 0); + if (!tmpret) + goto outdrbg; + test_data.fail_seed_source = 0; + + test_data.testentropy = &testentropy; + drbg_string_fill (&testentropy, test->entropy, test->entropylen); + /* overflow max addtllen with personalization string */ + tmpret = drbg_instantiate (drbg, &addtl, coreref, 0); + if (!tmpret) + goto outdrbg; + + dbg (("DRBG: Sanity tests for failure code paths successfully completed\n")); + ret = 0; + + outdrbg: + drbg_uninstantiate (drbg); + outbuf: + xfree (buf); + xfree (drbg); + return ret; +} + +/* + * DRBG Healthcheck function as required in SP800-90A + * + * return: + * 0 on success (all tests pass) + * >0 on error (return code indicate the number of failures) + */ +static int +drbg_healthcheck (void) +{ + int ret = 0; + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_nopr[0]); + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_nopr[1]); + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_nopr[2]); + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_nopr[3]); + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_nopr[4]); + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_pr[0]); + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_pr[1]); + ret += _gcry_rngdrbg_healthcheck_one (&drbg_test_pr[2]); + ret += drbg_healthcheck_sanity (&drbg_test_nopr[0]); + return ret; +} + +/* Run the self-tests. */ +gcry_error_t +_gcry_rngdrbg_selftest (selftest_report_func_t report) +{ + gcry_err_code_t ec; + const char *errtxt = NULL; + drbg_lock (); + if (0 != drbg_healthcheck ()) + errtxt = "RNG output does not match known value"; + drbg_unlock (); + if (report && errtxt) + report ("random", 0, "KAT", errtxt); + ec = errtxt ? GPG_ERR_SELFTEST_FAILED : 0; + return gpg_error (ec); +} + +/*************************************************************** + * Cipher invocations requested by DRBG + ***************************************************************/ + +static gpg_err_code_t +drbg_hash_init (drbg_state_t drbg) +{ + gcry_md_hd_t hd; + gpg_error_t err; + + err = _gcry_md_open (&hd, drbg->core->backend_cipher, 0); + if (err) + return err; + + drbg->priv_data = hd; + + return 0; +} + +static gpg_err_code_t +drbg_hmac_init (drbg_state_t drbg) +{ + gcry_md_hd_t hd; + gpg_error_t err; + + err = _gcry_md_open (&hd, drbg->core->backend_cipher, GCRY_MD_FLAG_HMAC); + if (err) + return err; + + drbg->priv_data = hd; + + return 0; +} + +static gpg_err_code_t +drbg_hmac_setkey (drbg_state_t drbg, const unsigned char *key) +{ + gcry_md_hd_t hd = (gcry_md_hd_t)drbg->priv_data; + + return _gcry_md_setkey (hd, key, drbg_statelen (drbg)); +} + +static void +drbg_hash_fini (drbg_state_t drbg) +{ + gcry_md_hd_t hd = (gcry_md_hd_t)drbg->priv_data; + + _gcry_md_close (hd); +} + +static byte * +drbg_hash (drbg_state_t drbg, const drbg_string_t *buf) +{ + gcry_md_hd_t hd = (gcry_md_hd_t)drbg->priv_data; + + _gcry_md_reset(hd); + for (; NULL != buf; buf = buf->next) + _gcry_md_write (hd, buf->buf, buf->len); + _gcry_md_final (hd); + return _gcry_md_read (hd, drbg->core->backend_cipher); +} + +static void +drbg_sym_fini (drbg_state_t drbg) +{ + gcry_cipher_hd_t hd = (gcry_cipher_hd_t)drbg->priv_data; + + if (hd) + _gcry_cipher_close (hd); + if (drbg->ctr_handle) + _gcry_cipher_close (drbg->ctr_handle); +} + +static gpg_err_code_t +drbg_sym_init (drbg_state_t drbg) +{ + gcry_cipher_hd_t hd; + gpg_error_t err; + + err = _gcry_cipher_open (&hd, drbg->core->backend_cipher, + GCRY_CIPHER_MODE_ECB, 0); + if (err) + { + drbg_sym_fini (drbg); + return err; + } + drbg->priv_data = hd; + + err = _gcry_cipher_open (&drbg->ctr_handle, drbg->core->backend_cipher, + GCRY_CIPHER_MODE_CTR, 0); + if (err) + { + drbg_sym_fini (drbg); + return err; + } + + + if (drbg_blocklen (drbg) != + _gcry_cipher_get_algo_blklen (drbg->core->backend_cipher)) + { + drbg_sym_fini (drbg); + return -GPG_ERR_NO_ERROR; + } + + return 0; +} + +static gpg_err_code_t +drbg_sym_setkey (drbg_state_t drbg, const unsigned char *key) +{ + gcry_cipher_hd_t hd = (gcry_cipher_hd_t)drbg->priv_data; + + return _gcry_cipher_setkey (hd, key, drbg_keylen (drbg)); +} + +static gpg_err_code_t +drbg_sym (drbg_state_t drbg, unsigned char *outval, const drbg_string_t *buf) +{ + gcry_cipher_hd_t hd = (gcry_cipher_hd_t)drbg->priv_data; + + _gcry_cipher_reset(hd); + if (drbg_blocklen (drbg) < buf->len) + return -GPG_ERR_NO_ERROR; + /* in is only component */ + return _gcry_cipher_encrypt (hd, outval, drbg_blocklen (drbg), buf->buf, + buf->len); +} + +static gpg_err_code_t +drbg_sym_ctr (drbg_state_t drbg, + const unsigned char *inbuf, unsigned int inbuflen, + unsigned char *outbuf, unsigned int outbuflen) +{ + gpg_error_t err; + + _gcry_cipher_reset(drbg->ctr_handle); + err = _gcry_cipher_setctr(drbg->ctr_handle, drbg->V, drbg_blocklen (drbg)); + if (err) + return err; + + while (outbuflen) + { + unsigned int cryptlen = (inbuflen > outbuflen) ? outbuflen : inbuflen; + + err = _gcry_cipher_encrypt (drbg->ctr_handle, outbuf, cryptlen, inbuf, + cryptlen); + if (err) + return err; + + outbuflen -= cryptlen; + outbuf += cryptlen; + } + return _gcry_cipher_getctr(drbg->ctr_handle, drbg->V, drbg_blocklen (drbg)); +} diff --git a/comm/third_party/libgcrypt/random/random-system.c b/comm/third_party/libgcrypt/random/random-system.c new file mode 100644 index 0000000000..8b79511c64 --- /dev/null +++ b/comm/third_party/libgcrypt/random/random-system.c @@ -0,0 +1,250 @@ +/* random-system.c - wrapper around the system's RNG + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + This RNG is merely wrapper around the system's native RNG. For + example on Unix systems it directly uses /dev/{u,}random. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> +#ifdef HAVE_GETTIMEOFDAY +#include <sys/time.h> +#endif + +#include "g10lib.h" +#include "random.h" +#include "rand-internal.h" + +/* This is the lock we use to serialize access to this RNG. The extra + integer variable is only used to check the locking state; that is, + it is not meant to be thread-safe but merely as a failsafe feature + to assert proper locking. */ +GPGRT_LOCK_DEFINE (system_rng_lock); +static int system_rng_is_locked; + + +/* --- Local prototypes --- */ + + + + +/* --- Functions --- */ + +/* Basic initialization is required to initialize mutexes and + do a few checks on the implementation. */ +static void +basic_initialization (void) +{ + static int initialized; + + if (initialized) + return; + initialized = 1; + + system_rng_is_locked = 0; + + /* Make sure that we are still using the values we traditionally + used for the random levels. */ + gcry_assert (GCRY_WEAK_RANDOM == 0 + && GCRY_STRONG_RANDOM == 1 + && GCRY_VERY_STRONG_RANDOM == 2); + +} + + +/* Acquire the system_rng_lock. */ +static void +lock_rng (void) +{ + gpg_err_code_t rc; + + rc = gpgrt_lock_lock (&system_rng_lock); + if (rc) + log_fatal ("failed to acquire the System RNG lock: %s\n", + gpg_strerror (rc)); + system_rng_is_locked = 1; +} + + +/* Release the system_rng_lock. */ +static void +unlock_rng (void) +{ + gpg_err_code_t rc; + + system_rng_is_locked = 0; + rc = gpgrt_lock_unlock (&system_rng_lock); + if (rc) + log_fatal ("failed to release the System RNG lock: %s\n", + gpg_strerror (rc)); +} + + +/* Helper variables for read_cb(). + + The _gcry_rnd*_gather_random interface does not allow to provide a + data pointer. Thus we need to use a global variable for + communication. However, the then required locking is anyway a good + idea because it does not make sense to have several readers of (say + /dev/random). It is easier to serve them one after the other. */ +static unsigned char *read_cb_buffer; /* The buffer. */ +static size_t read_cb_size; /* Size of the buffer. */ +static size_t read_cb_len; /* Used length. */ + + +/* Callback for _gcry_rnd*_gather_random. */ +static void +read_cb (const void *buffer, size_t length, enum random_origins origin) +{ + const unsigned char *p = buffer; + + (void)origin; + + gcry_assert (system_rng_is_locked); + gcry_assert (read_cb_buffer); + + /* Note that we need to protect against gatherers returning more + than the requested bytes (e.g. rndw32). */ + while (length-- && read_cb_len < read_cb_size) + { + read_cb_buffer[read_cb_len++] = *p++; + } +} + + +/* Fill BUFFER with LENGTH bytes of random at quality LEVEL. The + function either succeeds or terminates the process in case of a + fatal error. */ +static void +get_random (void *buffer, size_t length, int level) +{ + int rc; + + gcry_assert (buffer); + + read_cb_buffer = buffer; + read_cb_size = length; + read_cb_len = 0; + +#if USE_RNDLINUX + rc = _gcry_rndlinux_gather_random (read_cb, 0, length, level); +#elif USE_RNDUNIX + rc = _gcry_rndunix_gather_random (read_cb, 0, length, level); +#elif USE_RNDW32 + do + { + rc = _gcry_rndw32_gather_random (read_cb, 0, length, level); + } + while (rc >= 0 && read_cb_len < read_cb_size); +#else + rc = -1; +#endif + + if (rc < 0 || read_cb_len != read_cb_size) + { + log_fatal ("error reading random from system RNG (rc=%d)\n", rc); + } +} + + + +/* --- Public Functions --- */ + +/* 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 + in a threaded environment we might get a race condition + otherwise. */ +void +_gcry_rngsystem_initialize (int full) +{ + basic_initialization (); + if (!full) + return; + /* Nothing more to initialize. */ + return; +} + + +/* Try to close the FDs of the random gather module. This is + currently only implemented for rndlinux. */ +void +_gcry_rngsystem_close_fds (void) +{ + lock_rng (); +#if USE_RNDLINUX + _gcry_rndlinux_gather_random (NULL, 0, 0, 0); +#endif + unlock_rng (); +} + + +/* Print some statistics about the RNG. */ +void +_gcry_rngsystem_dump_stats (void) +{ + /* Not yet implemented. */ +} + + +/* This function returns true if no real RNG is available or the + quality of the RNG has been degraded for test purposes. */ +int +_gcry_rngsystem_is_faked (void) +{ + return 0; /* Faked random is not supported. */ +} + + +/* 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. */ +gcry_error_t +_gcry_rngsystem_add_bytes (const void *buf, size_t buflen, int quality) +{ + (void)buf; + (void)buflen; + (void)quality; + return 0; /* Not implemented. */ +} + + +/* Public function to fill the buffer with LENGTH bytes of + cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is + here mapped to GCRY_STRONG_RANDOM, GCRY_STRONG_RANDOM is strong + enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key + generation stuff but may be very slow. */ +void +_gcry_rngsystem_randomize (void *buffer, size_t length, + enum gcry_random_level level) +{ + _gcry_rngsystem_initialize (1); /* Auto-initialize if needed. */ + + if (level != GCRY_VERY_STRONG_RANDOM) + level = GCRY_STRONG_RANDOM; + + lock_rng (); + get_random (buffer, length, level); + unlock_rng (); +} diff --git a/comm/third_party/libgcrypt/random/random.c b/comm/third_party/libgcrypt/random/random.c new file mode 100644 index 0000000000..9aab78930b --- /dev/null +++ b/comm/third_party/libgcrypt/random/random.c @@ -0,0 +1,584 @@ +/* random.c - Random number switch + * Copyright (C) 2003, 2006, 2008, 2012 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + This module switches between different implementations of random + number generators and provides a few help functions. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <time.h> +#include <sys/types.h> +#include <unistd.h> +#ifdef HAVE_SYSLOG +# include <syslog.h> +#endif /*HAVE_SYSLOG*/ +#include <ctype.h> + +#include "g10lib.h" +#include "random.h" +#include "rand-internal.h" +#include "cipher.h" /* For _gcry_sha1_hash_buffer(). */ + +/* The name of a file used to globally configure the RNG. */ +#define RANDOM_CONF_FILE "/etc/gcrypt/random.conf" + + +/* If not NULL a progress function called from certain places and the + opaque value passed along. Registered by + _gcry_register_random_progress (). */ +static void (*progress_cb) (void *,const char*,int,int, int ); +static void *progress_cb_data; + +/* Flags indicating the requested RNG types. */ +static struct +{ + int standard; + int fips; + int system; +} rng_types; + + +/* This is the lock we use to protect the buffer used by the nonce + generation. */ +GPGRT_LOCK_DEFINE (nonce_buffer_lock); + + + +/* --- Functions --- */ + + +/* Used to register a progress callback. This needs to be called + before any threads are created. */ +void +_gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int), + void *cb_data ) +{ + progress_cb = cb; + progress_cb_data = cb_data; +} + + +/* This progress function is currently used by the random modules to + give hints on how much more entropy is required. */ +void +_gcry_random_progress (const char *what, int printchar, int current, int total) +{ + if (progress_cb) + progress_cb (progress_cb_data, what, printchar, current, total); +} + + +/* Read a file with configure options. The file is a simple text file + * where empty lines and lines with the first non white-space + * character being '#' are ignored. Supported configure options are: + * + * disable-jent - Disable the jitter based extra entropy generator. + * This sets the RANDOM_CONF_DISABLE_JENT bit. + * only-urandom - Always use /dev/urandom instead of /dev/random. + * This sets the RANDOM_CONF_ONLY_URANDOM bit. + * + * The function returns a bit vector with flags read from the file. + */ +unsigned int +_gcry_random_read_conf (void) +{ + const char *fname = RANDOM_CONF_FILE; + FILE *fp; + char buffer[256]; + char *p, *pend; + int lnr = 0; + unsigned int result = 0; + + fp = fopen (fname, "r"); + if (!fp) + return result; + + for (;;) + { + if (!fgets (buffer, sizeof buffer, fp)) + { + if (!feof (fp)) + { +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, + "Libgcrypt warning: error reading '%s', line %d", + fname, lnr); +#endif /*HAVE_SYSLOG*/ + } + fclose (fp); + return result; + } + lnr++; + for (p=buffer; my_isascii (*p) && isspace (*p); p++) + ; + pend = strchr (p, '\n'); + if (pend) + *pend = 0; + pend = p + (*p? (strlen (p)-1):0); + for ( ;pend > p; pend--) + if (my_isascii (*pend) && isspace (*pend)) + *pend = 0; + if (!*p || *p == '#') + continue; + + if (!strcmp (p, "disable-jent")) + result |= RANDOM_CONF_DISABLE_JENT; + else if (!strcmp (p, "only-urandom")) + result |= RANDOM_CONF_ONLY_URANDOM; + else + { +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, + "Libgcrypt warning: unknown option in '%s', line %d", + fname, lnr); +#endif /*HAVE_SYSLOG*/ + } + } +} + + +/* Set the preferred RNG type. This may be called at any time even + before gcry_check_version. Thus we can't assume any thread system + initialization. A type of 0 is used to indicate that any Libgcrypt + initialization has been done.*/ +void +_gcry_set_preferred_rng_type (int type) +{ + static int any_init; + + if (!type) + { + any_init = 1; + } + else if (type == GCRY_RNG_TYPE_STANDARD) + { + rng_types.standard = 1; + } + else if (any_init) + { + /* After any initialization has been done we only allow to + upgrade to the standard RNG (handled above). All other + requests are ignored. The idea is that the application needs + to declare a preference for a weaker RNG as soon as possible + and before any library sets a preference. We assume that a + library which uses Libgcrypt calls an init function very + early. This way --- even if the library gets initialized + early by the application --- it is unlikely that it can + select a lower priority RNG. + + This scheme helps to ensure that existing unmodified + applications (e.g. gpg2), which don't known about the new RNG + selection system, will continue to use the standard RNG and + not be tricked by some library to use a lower priority RNG. + There are some loopholes here but at least most GnuPG stuff + should be save because it calls src_c{gcry_control + (GCRYCTL_SUSPEND_SECMEM_WARN);} quite early and thus inhibits + switching to a low priority RNG. + */ + } + else if (type == GCRY_RNG_TYPE_FIPS) + { + rng_types.fips = 1; + } + else if (type == GCRY_RNG_TYPE_SYSTEM) + { + rng_types.system = 1; + } +} + + +/* 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 + in a threaded environment we might get a race condition + otherwise. */ +void +_gcry_random_initialize (int full) +{ + if (fips_mode ()) + _gcry_rngdrbg_inititialize (full); + else if (rng_types.standard) + _gcry_rngcsprng_initialize (full); + else if (rng_types.fips) + _gcry_rngdrbg_inititialize (full); + else if (rng_types.system) + _gcry_rngsystem_initialize (full); + else + _gcry_rngcsprng_initialize (full); +} + + +/* If possible close file descriptors used by the RNG. */ +void +_gcry_random_close_fds (void) +{ + /* Note that we can't do that directly because each random system + has its own lock functions which need to be used for accessing + the entropy gatherer. */ + + if (fips_mode ()) + _gcry_rngdrbg_close_fds (); + else if (rng_types.standard) + _gcry_rngcsprng_close_fds (); + else if (rng_types.fips) + _gcry_rngdrbg_close_fds (); + else if (rng_types.system) + _gcry_rngsystem_close_fds (); + else + _gcry_rngcsprng_close_fds (); +} + + +/* Return the current RNG type. IGNORE_FIPS_MODE is a flag used to + skip the test for FIPS. This is useful, so that we are able to + return the type of the RNG even before we have setup FIPS mode + (note that FIPS mode is enabled by default until it is switched off + by the initialization). This is mostly useful for the regression + test. */ +int +_gcry_get_rng_type (int ignore_fips_mode) +{ + if (!ignore_fips_mode && fips_mode ()) + return GCRY_RNG_TYPE_FIPS; + else if (rng_types.standard) + return GCRY_RNG_TYPE_STANDARD; + else if (rng_types.fips) + return GCRY_RNG_TYPE_FIPS; + else if (rng_types.system) + return GCRY_RNG_TYPE_SYSTEM; + else + return GCRY_RNG_TYPE_STANDARD; +} + + +void +_gcry_random_dump_stats (void) +{ + if (fips_mode ()) + _gcry_rngdrbg_dump_stats (); + else + _gcry_rngcsprng_dump_stats (); + _gcry_rndjent_dump_stats (); +} + + +/* This function should be called during initialization and before + initialization of this module to place the random pools into secure + memory. */ +void +_gcry_secure_random_alloc (void) +{ + if (fips_mode ()) + ; /* Not used; the FIPS RNG is always in secure mode. */ + else + _gcry_rngcsprng_secure_alloc (); +} + + +/* This may be called before full initialization to degrade the + quality of the RNG for the sake of a faster running test suite. */ +void +_gcry_enable_quick_random_gen (void) +{ + if (fips_mode ()) + ; /* Not used. */ + else + _gcry_rngcsprng_enable_quick_gen (); +} + + +void +_gcry_set_random_daemon_socket (const char *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 + to 0, disable the use of the daemon. With ONOF set to -1, return + whether the daemon has been enabled. */ +int +_gcry_use_random_daemon (int onoff) +{ + if (fips_mode ()) + return 0; /* Never enabled in fips mode. */ + else + return _gcry_rngcsprng_use_daemon (onoff); +} + + +/* This function returns true if no real RNG is available or the + quality of the RNG has been degraded for test purposes. */ +int +_gcry_random_is_faked (void) +{ + if (fips_mode ()) + return _gcry_rngdrbg_is_faked (); + else + return _gcry_rngcsprng_is_faked (); +} + + +/* 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. */ +gcry_err_code_t +_gcry_random_add_bytes (const void *buf, size_t buflen, int quality) +{ + if (fips_mode ()) + return 0; /* No need for this in fips mode. */ + else if (rng_types.standard) + return gpg_err_code (_gcry_rngcsprng_add_bytes (buf, buflen, quality)); + else if (rng_types.fips) + return 0; + else if (rng_types.system) + return 0; + else /* default */ + return gpg_err_code (_gcry_rngcsprng_add_bytes (buf, buflen, quality)); +} + + +/* Helper function. */ +static void +do_randomize (void *buffer, size_t length, enum gcry_random_level level) +{ + if (fips_mode ()) + _gcry_rngdrbg_randomize (buffer, length, level); + else if (rng_types.standard) + _gcry_rngcsprng_randomize (buffer, length, level); + else if (rng_types.fips) + _gcry_rngdrbg_randomize (buffer, length, level); + else if (rng_types.system) + _gcry_rngsystem_randomize (buffer, length, level); + else /* default */ + _gcry_rngcsprng_randomize (buffer, length, level); +} + +/* The public function to return random data of the quality LEVEL. + Returns a pointer to a newly allocated and randomized buffer of + LEVEL and NBYTES length. Caller must free the buffer. */ +void * +_gcry_random_bytes (size_t nbytes, enum gcry_random_level level) +{ + void *buffer; + + buffer = xmalloc (nbytes); + do_randomize (buffer, nbytes, level); + return buffer; +} + + +/* The public function to return random data of the quality LEVEL; + this version of the function returns the random in a buffer allocated + in secure memory. Caller must free the buffer. */ +void * +_gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level) +{ + void *buffer; + + /* Historical note (1.3.0--1.4.1): The buffer was only allocated + in secure memory if the pool in random-csprng.c was also set to + use secure memory. */ + buffer = xmalloc_secure (nbytes); + do_randomize (buffer, nbytes, level); + return buffer; +} + + +/* Public function to fill the buffer with LENGTH bytes of + cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is + not very strong, GCRY_STRONG_RANDOM is strong enough for most + usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but + may be very slow. */ +void +_gcry_randomize (void *buffer, size_t length, enum gcry_random_level level) +{ + do_randomize (buffer, length, level); +} + + +/* This function may be used to specify the file to be used as a seed + file for the PRNG. This function should be called prior to the + initialization of the random module. NAME may not be NULL. */ +void +_gcry_set_random_seed_file (const char *name) +{ + if (fips_mode ()) + ; /* No need for this in fips mode. */ + else if (rng_types.standard) + _gcry_rngcsprng_set_seed_file (name); + else if (rng_types.fips) + ; + else if (rng_types.system) + ; + else /* default */ + _gcry_rngcsprng_set_seed_file (name); +} + + +/* If a seed file has been setup, this function may be used to write + back the random numbers entropy pool. */ +void +_gcry_update_random_seed_file (void) +{ + if (fips_mode ()) + ; /* No need for this in fips mode. */ + else if (rng_types.standard) + _gcry_rngcsprng_update_seed_file (); + else if (rng_types.fips) + ; + else if (rng_types.system) + ; + else /* default */ + _gcry_rngcsprng_update_seed_file (); +} + + + +/* The fast random pool function as called at some places in + libgcrypt. This is merely a wrapper to make sure that this module + is initialized and to lock the pool. Note, that this function is a + NOP unless a random function has been used or _gcry_initialize (1) + has been used. We use this hack so that the internal use of this + function in cipher_open and md_open won't start filling up the + random pool, even if no random will be required by the process. */ +void +_gcry_fast_random_poll (void) +{ + if (fips_mode ()) + ; /* No need for this in fips mode. */ + else if (rng_types.standard) + _gcry_rngcsprng_fast_poll (); + else if (rng_types.fips) + ; + else if (rng_types.system) + ; + else /* default */ + _gcry_rngcsprng_fast_poll (); +} + + + +/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ +void +_gcry_create_nonce (void *buffer, size_t length) +{ + static unsigned char nonce_buffer[20+8]; + static int nonce_buffer_initialized = 0; + static volatile pid_t my_pid; /* The volatile is there to make sure the + compiler does not optimize the code away + in case the getpid function is badly + attributed. */ + volatile pid_t apid; + unsigned char *p; + size_t n; + int err; + + /* First check whether we shall use the FIPS nonce generator. This + is only done in FIPS mode, in all other modes, we use our own + nonce generator which is seeded by the RNG actual in use. */ + if (fips_mode ()) + { + _gcry_rngdrbg_randomize (buffer, length, GCRY_WEAK_RANDOM); + return; + } + + /* This is the nonce generator, which formerly lived in + random-csprng.c. It is now used by all RNG types except when in + FIPS mode (not that this means it is also used if the FIPS RNG + has been selected but we are not in fips mode). */ + + /* Make sure we are initialized. */ + _gcry_random_initialize (1); + + /* Acquire the nonce buffer lock. */ + err = gpgrt_lock_lock (&nonce_buffer_lock); + if (err) + log_fatal ("failed to acquire the nonce buffer lock: %s\n", + gpg_strerror (err)); + + apid = getpid (); + /* The first time initialize our buffer. */ + if (!nonce_buffer_initialized) + { + time_t atime = time (NULL); + pid_t xpid = apid; + + my_pid = apid; + + if ((sizeof apid + sizeof atime) > sizeof nonce_buffer) + BUG (); + + /* Initialize the first 20 bytes with a reasonable value so that + a failure of gcry_randomize won't affect us too much. Don't + care about the uninitialized remaining bytes. */ + p = nonce_buffer; + memcpy (p, &xpid, sizeof xpid); + p += sizeof xpid; + memcpy (p, &atime, sizeof atime); + + /* Initialize the never changing private part of 64 bits. */ + _gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); + + nonce_buffer_initialized = 1; + } + else if ( my_pid != apid ) + { + /* We forked. Need to reseed the buffer - doing this for the + private part should be sufficient. */ + do_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); + /* Update the pid so that we won't run into here again and + again. */ + my_pid = apid; + } + + /* Create the nonce by hashing the entire buffer, returning the hash + and updating the first 20 bytes of the buffer with this hash. */ + for (p = buffer; length > 0; length -= n, p += n) + { + _gcry_sha1_hash_buffer (nonce_buffer, + nonce_buffer, sizeof nonce_buffer); + n = length > 20? 20 : length; + memcpy (p, nonce_buffer, n); + } + + /* Release the nonce buffer lock. */ + err = gpgrt_lock_unlock (&nonce_buffer_lock); + if (err) + log_fatal ("failed to release the nonce buffer lock: %s\n", + gpg_strerror (err)); +} + + +/* 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_rngdrbg_selftest (report); + else + return 0; /* No selftests yet. */ +} diff --git a/comm/third_party/libgcrypt/random/random.h b/comm/third_party/libgcrypt/random/random.h new file mode 100644 index 0000000000..c00b9ed537 --- /dev/null +++ b/comm/third_party/libgcrypt/random/random.h @@ -0,0 +1,79 @@ +/* random.h - random functions + * Copyright (C) 1998, 2002, 2006 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_RANDOM_H +#define G10_RANDOM_H + +#include "types.h" +#include "../src/gcrypt-testapi.h" /* struct gcry_drbg_test_vector */ + +/*-- random.c --*/ +void _gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int), + void *cb_data ); + +void _gcry_set_preferred_rng_type (int type); +void _gcry_random_initialize (int full); +void _gcry_random_close_fds (void); +int _gcry_get_rng_type (int ignore_fips_mode); +void _gcry_random_dump_stats(void); +void _gcry_secure_random_alloc(void); +void _gcry_enable_quick_random_gen (void); +int _gcry_random_is_faked(void); +void _gcry_set_random_daemon_socket (const char *socketname); +int _gcry_use_random_daemon (int onoff); +void _gcry_set_random_seed_file (const char *name); +void _gcry_update_random_seed_file (void); + +void _gcry_fast_random_poll( void ); + +gcry_err_code_t _gcry_random_init_external_test (void **r_context, + unsigned int flags, + const void *key, + size_t keylen, + const void *seed, + size_t seedlen, + const void *dt, + size_t dtlen); +gcry_err_code_t _gcry_random_run_external_test (void *context, + char *buffer, size_t buflen); +void _gcry_random_deinit_external_test (void *context); + +/*-- random-drbg.c --*/ +gpg_err_code_t _gcry_rngdrbg_reinit (const char *flagstr, + gcry_buffer_t *pers, int npers); +gpg_err_code_t _gcry_rngdrbg_cavs_test (struct gcry_drbg_test_vector *t, + unsigned char *buf); +gpg_err_code_t _gcry_rngdrbg_healthcheck_one (struct gcry_drbg_test_vector *t); + +/*-- rndegd.c --*/ +gpg_error_t _gcry_rndegd_set_socket_name (const char *name); + +/*-- rndjent.c --*/ +unsigned int _gcry_rndjent_get_version (int *r_active); + + +/*-- random-daemon.c (only used from random.c) --*/ +#ifdef USE_RANDOM_DAEMON +void _gcry_daemon_initialize_basics (void); +int _gcry_daemon_randomize (const char *socketname, + void *buffer, size_t length, + enum gcry_random_level level); +#endif /*USE_RANDOM_DAEMON*/ + +#endif /*G10_RANDOM_H*/ diff --git a/comm/third_party/libgcrypt/random/rndegd.c b/comm/third_party/libgcrypt/random/rndegd.c new file mode 100644 index 0000000000..b87115f234 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndegd.c @@ -0,0 +1,290 @@ +/* rndegd.c - interface to the EGD + * Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "rand-internal.h" + +#ifndef offsetof +#define offsetof(type, member) ((size_t) &((type *)0)->member) +#endif + +static int egd_socket = -1; + +/* Allocated name of the socket if supplied at runtime. */ +static char *user_socket_name; + + +/* Allocate a new filename from FIRST_PART and SECOND_PART and to + tilde expansion for first_part. SECOND_PART might be NULL. + */ +static char * +my_make_filename (const char *first_part, const char *second_part) +{ + size_t n; + char *name, *home, *p; + + n = strlen(first_part)+1; + if (second_part) + n += strlen (second_part) + 1; + + home = NULL; + if( *first_part == '~' && first_part[1] == '/' + && (home = getenv("HOME")) && *home ) + n += strlen(home); + + name = _gcry_xmalloc(n); + p = (home + ? stpcpy (stpcpy (name, home), first_part+1 ) + : stpcpy (name, first_part) ); + + if (second_part) + strcpy (stpcpy(p,"/"), second_part); + + return name; +} + + +static int +do_write( int fd, void *buf, size_t nbytes ) +{ + size_t nleft = nbytes; + int nwritten; + + while( nleft > 0 ) + { + nwritten = write( fd, buf, nleft); + if( nwritten < 0 ) + { + if( errno == EINTR ) + continue; + return -1; + } + nleft -= nwritten; + buf = (char*)buf + nwritten; + } + return 0; +} + +static int +do_read( int fd, void *buf, size_t nbytes ) +{ + int n, nread = 0; + + do + { + do + { + n = read(fd, (char*)buf + nread, nbytes ); + } + while( n == -1 && errno == EINTR ); + if( n == -1) + return nread? nread:-1; + if( n == 0) + return -1; + nread += n; + nbytes -= n; + } + while( nread < nbytes ); + return nread; +} + + +/* Note that his function is not thread-safe. */ +gpg_error_t +_gcry_rndegd_set_socket_name (const char *name) +{ + char *newname; + struct sockaddr_un addr; + + newname = my_make_filename (name, NULL); + if (strlen (newname)+1 >= sizeof addr.sun_path) + { + xfree (newname); + return gpg_error_from_syserror (); + } + xfree (user_socket_name); + user_socket_name = newname; + return 0; +} + + +/* Connect to the EGD and return the file descriptor. Return -1 on + error. With NOFAIL set to true, silently fail and return the + error, otherwise print an error message and die. */ +int +_gcry_rndegd_connect_socket (int nofail) +{ + int fd; + const char *bname = NULL; + char *name; + struct sockaddr_un addr; + int addr_len; + + if (egd_socket != -1) + { + close (egd_socket); + egd_socket = -1; + } + +#ifdef EGD_SOCKET_NAME + bname = EGD_SOCKET_NAME; +#endif + if (user_socket_name) + { + name = _gcry_strdup (user_socket_name); + if (!name) + { + if (!nofail) + log_fatal ("error allocating memory in rndegd: %s\n", + strerror(errno) ); + return -1; + } + } + else if ( !bname || !*bname ) + name = my_make_filename ("~/.gnupg", "entropy"); + else + name = my_make_filename (bname, NULL); + + if (strlen(name)+1 >= sizeof addr.sun_path) + log_fatal ("EGD socketname is too long\n"); + + memset( &addr, 0, sizeof addr ); + addr.sun_family = AF_UNIX; + strcpy( addr.sun_path, name ); + addr_len = (offsetof( struct sockaddr_un, sun_path ) + + strlen( addr.sun_path )); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1 && !nofail) + log_fatal("can't create unix domain socket: %s\n", strerror(errno) ); + else if (connect (fd, (struct sockaddr*)&addr, addr_len) == -1) + { + if (!nofail) + log_fatal("can't connect to EGD socket `%s': %s\n", + name, strerror(errno) ); + close (fd); + fd = -1; + } + xfree (name); + if (fd != -1) + egd_socket = fd; + return fd; +} + +/**************** + * Note: We always use the highest level. + * To boost the performance we may want to add some + * additional code for level 1 + * + * Using a level of 0 should never block and better add nothing + * to the pool. So this is just a dummy for EGD. + */ +int +_gcry_rndegd_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + int fd = egd_socket; + int n; + byte buffer[256+2]; + int nbytes; + int do_restart = 0; + + if( !length ) + return 0; + if( !level ) + return 0; + + restart: + if (fd == -1 || do_restart) + fd = _gcry_rndegd_connect_socket (0); + + do_restart = 0; + + nbytes = length < 255? length : 255; + /* First time we do it with a non blocking request */ + buffer[0] = 1; /* non blocking */ + buffer[1] = nbytes; + if( do_write( fd, buffer, 2 ) == -1 ) + log_fatal("can't write to the EGD: %s\n", strerror(errno) ); + n = do_read( fd, buffer, 1 ); + if( n == -1 ) + { + log_error("read error on EGD: %s\n", strerror(errno)); + do_restart = 1; + goto restart; + } + n = buffer[0]; + if( n ) + { + n = do_read( fd, buffer, n ); + if( n == -1 ) + { + log_error("read error on EGD: %s\n", strerror(errno)); + do_restart = 1; + goto restart; + } + (*add)( buffer, n, origin ); + length -= n; + } + + if( length ) + { + log_info ( + _("Please wait, entropy is being gathered. Do some work if it would\n" + "keep you from getting bored, because it will improve the quality\n" + "of the entropy.\n") ); + } + while( length ) + { + nbytes = length < 255? length : 255; + + buffer[0] = 2; /* blocking */ + buffer[1] = nbytes; + if( do_write( fd, buffer, 2 ) == -1 ) + log_fatal("can't write to the EGD: %s\n", strerror(errno) ); + n = do_read( fd, buffer, nbytes ); + if( n == -1 ) + { + log_error("read error on EGD: %s\n", strerror(errno)); + do_restart = 1; + goto restart; + } + (*add)( buffer, n, origin ); + length -= n; + } + memset(buffer, 0, sizeof(buffer) ); + + return 0; /* success */ +} diff --git a/comm/third_party/libgcrypt/random/rndhw.c b/comm/third_party/libgcrypt/random/rndhw.c new file mode 100644 index 0000000000..3cf9acc3a2 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndhw.c @@ -0,0 +1,230 @@ +/* rndhw.c - Access to the external random daemon + * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright (C) 2012 Dmitry Kasatkin + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + +#undef USE_PADLOCK +#ifdef ENABLE_PADLOCK_SUPPORT +# ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__) +# define USE_PADLOCK 1 +# endif +# endif +#endif /*ENABLE_PADLOCK_SUPPORT*/ + +#undef USE_DRNG +#ifdef ENABLE_DRNG_SUPPORT +# ifdef HAVE_GCC_ATTRIBUTE_ALIGNED +# if (defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__) +# define USE_DRNG 1 +# endif +# endif +#endif /*ENABLE_RDRAND_SUPPORT*/ + +typedef void (*add_fn_t)(const void*, size_t, enum random_origins); + +/* Keep track on whether the RNG has problems. */ +static volatile int rng_failed; + + +#ifdef USE_PADLOCK +static size_t +poll_padlock (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin, int fast) +{ + volatile char buffer[64+8] __attribute__ ((aligned (8))); + volatile char *p; + unsigned int nbytes, status; + + /* Peter Gutmann's cryptlib tests again whether the RNG is enabled + but we don't do so. We would have to do this also for our AES + implementation and that is definitely too time consuming. There + would be a race condition anyway. Thus we assume that the OS + does not change the Padlock initialization while a user process + is running. */ + p = buffer; + nbytes = 0; + while (nbytes < 64) + { +#if defined(__x86_64__) && SIZEOF_VOID_P == 8 + asm volatile + ("movq %1, %%rdi\n\t" /* Set buffer. */ + "xorq %%rdx, %%rdx\n\t" /* Request up to 8 bytes. */ + ".byte 0x0f, 0xa7, 0xc0\n\t" /* XSTORE RNG. */ + : "=a" (status) + : "g" (p) + : "%rdx", "%rdi", "cc", "memory" + ); +#else + asm volatile + ("movl %1, %%edi\n\t" /* Set buffer. */ + "xorl %%edx, %%edx\n\t" /* Request up to 8 bytes. */ + ".byte 0x0f, 0xa7, 0xc0\n\t" /* XSTORE RNG. */ + : "=a" (status) + : "g" (p) + : "%edx", "%edi", "cc", "memory" + ); +#endif + if ((status & (1<<6)) /* RNG still enabled. */ + && !(status & (1<<13)) /* von Neumann corrector is enabled. */ + && !(status & (1<<14)) /* String filter is disabled. */ + && !(status & 0x1c00) /* BIAS voltage at default. */ + && (!(status & 0x1f) || (status & 0x1f) == 8) /* Sanity check. */ + ) + { + nbytes += (status & 0x1f); + if (fast) + break; /* Don't get into the loop with the fast flag set. */ + p += (status & 0x1f); + } + else + { + /* If there was an error we need to break the loop and + record that there is something wrong with the padlock + RNG. */ + rng_failed = 1; + break; + } + } + + if (nbytes) + { + (*add) ((void*)buffer, nbytes, origin); + wipememory (buffer, nbytes); + } + return nbytes; +} +#endif /*USE_PADLOCK*/ + + +#ifdef USE_DRNG +# define RDRAND_RETRY_LOOPS 10 +# define RDRAND_INT ".byte 0x0f,0xc7,0xf0" +# if defined(__x86_64__) && SIZEOF_UNSIGNED_LONG == 8 +# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0" +# else +# define RDRAND_LONG RDRAND_INT +# endif +static inline int +rdrand_long (volatile unsigned long *v) +{ + int ok; + asm volatile ("1: " RDRAND_LONG "\n\t" + "jc 2f\n\t" + "decl %0\n\t" + "jnz 1b\n\t" + "2:" + : "=r" (ok), "=a" (*v) + : "0" (RDRAND_RETRY_LOOPS) + : "cc", "memory"); + return ok; +} + + +static inline int +rdrand_nlong (volatile unsigned long *v, int count) +{ + while (count--) + if (!rdrand_long(v++)) + return 0; + return 1; +} + + +static size_t +poll_drng (add_fn_t add, enum random_origins origin, int fast) +{ + volatile unsigned long buffer[8] __attribute__ ((aligned (8))); + unsigned int nbytes = sizeof (buffer); + + (void)fast; + + if (!rdrand_nlong (buffer, DIM(buffer))) + return 0; + (*add)((void *)buffer, nbytes, origin); + return nbytes; +} +#endif /*USE_DRNG*/ + + +int +_gcry_rndhw_failed_p (void) +{ + return rng_failed; +} + + +/* Try to read random from a hardware RNG if a fast one is + available. */ +void +_gcry_rndhw_poll_fast (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin) +{ + (void)add; + (void)origin; + +#ifdef USE_DRNG + if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND)) + poll_drng (add, origin, 1); +#endif +#ifdef USE_PADLOCK + if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG)) + poll_padlock (add, origin, 1); +#endif +} + + +/* Read 64 bytes from a hardware RNG and return the number of bytes + actually read. However hardware source is let account only + for up to 50% (or 25% for RDRAND) of the requested bytes. */ +size_t +_gcry_rndhw_poll_slow (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin, size_t req_length) +{ + size_t nbytes = 0; + + (void)add; + (void)origin; + + req_length /= 2; /* Up to 50%. */ + +#ifdef USE_DRNG + if ((_gcry_get_hw_features () & HWF_INTEL_RDRAND)) + { + req_length /= 2; /* Up to 25%. */ + nbytes += poll_drng (add, origin, 0); + } +#endif +#ifdef USE_PADLOCK + if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG)) + nbytes += poll_padlock (add, origin, 0); +#endif + + if (nbytes > req_length) + nbytes = req_length; + + return nbytes; +} diff --git a/comm/third_party/libgcrypt/random/rndjent.c b/comm/third_party/libgcrypt/random/rndjent.c new file mode 100644 index 0000000000..56648a8756 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndjent.c @@ -0,0 +1,389 @@ +/* rndjent.c - Driver for the jitterentropy module. + * Copyright (C) 2017 g10 Code GmbH + * Copyright (C) 2017 Bundesamt für Sicherheit in der Informationstechnik + * Copyright (C) 2013 Stephan Mueller <smueller@chronox.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif + +#include "types.h" +#include "g10lib.h" +#include "../cipher/bithelp.h" +#include "rand-internal.h" + +/* + * Decide whether we can support jent at compile time. + */ +#undef USE_JENT +#define JENT_USES_RDTSC 1 +#define JENT_USES_GETTIME 2 +#define JENT_USES_READ_REAL_TIME 3 +#ifdef ENABLE_JENT_SUPPORT +# if (defined (__i386__) || defined(__x86_64__)) && defined(HAVE_CPU_ARCH_X86) +# define USE_JENT JENT_USES_RDTSC +# elif defined (HAVE_CLOCK_GETTIME) +# if _AIX +# define USE_JENT JENT_USES_READ_REAL_TIME +# else +# define USE_JENT JENT_USES_GETTIME +# endif +# endif +#endif /*ENABLE_JENT_SUPPORT*/ + + +#ifdef USE_JENT + +#undef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT +/* Uncomment the next line to build with statistics. */ +/* #define CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT 1 */ + + +/* Note that we source include the actual jitter entropy code. + * Platform dependent code is indirectly included from our own + * jitterentropy-user-base.h file. */ + +/* Tell jitterentropy* that all functions shall be static. */ +#define JENT_PRIVATE_COMPILE 1 + +#include "jitterentropy-base.c" + + +/* This is the lock we use to serialize access to this RNG. The extra + * integer variable is only used to check the locking state; that is, + * it is not meant to be thread-safe but merely as a failsafe feature + * to assert proper locking. */ +GPGRT_LOCK_DEFINE (jent_rng_lock); +static int jent_rng_is_locked; + +/* This flag tracks whether the RNG has been initialized - either + * with error or with success. Protected by JENT_RNG_LOCK. */ +static int jent_rng_is_initialized; + +/* Our collector. The RNG is in a working state if its value is not + * NULL. Protected by JENT_RNG_LOCK. */ +struct rand_data *jent_rng_collector; + +/* The number of times the core entropy function has been called and + * the number of random bytes retrieved. */ +static unsigned long jent_rng_totalcalls; +static unsigned long jent_rng_totalbytes; + + + +/* JENT statistic helper code. */ +#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT + +static void +jent_init_statistic (struct rand_data *rand_data) +{ + /* int i; */ + /* struct entropy_stat *stat = &rand_data->entropy_stat; */ + + /* for (i = 0; i < 64; i++) */ + /* { */ + /* stat->bitslot[i] = 0; */ + /* stat->bitvar[i] = 0; */ + /* } */ + + /* jent_get_nstime (&stat->collection_begin); */ +} + +static void +jent_bit_count (struct rand_data *rand_data, u64 prev_data) +{ + /* int i; */ + + /* if (!rand_data->entropy_stat.enable_bit_test) */ + /* return; */ + + /* for (i = 0; i < 64; i++) */ + /* { */ + /* /\* collect the count of set bits per bit position in the */ + /* * current ->data field *\/ */ + /* rand_data->entropy_stat.bitslot[i] += (rand_data->data & 1<<i) ? 1:0; */ + + /* /\* collect the count of bit changes between the current */ + /* * and the previous random data value per bit position *\/ */ + /* if ((rand_data->data & 1<<i) != (prev_data & 1<<i)) */ + /* rand_data->entropy_stat.bitvar[i] += 1; */ + /* } */ +} + + +static void +jent_statistic_copy_stat (struct entropy_stat *src, struct entropy_stat *dst) +{ + /* /\* not copying bitslot and bitvar as they are not needed for */ + /* * statistic printout *\/ */ + /* dst->collection_begin = src->collection_begin; */ + /* dst->collection_end = src->collection_end; */ + /* dst->old_delta = src->old_delta; */ + /* dst->setbits = src->setbits; */ + /* dst->varbits = src->varbits; */ + /* dst->obsbits = src->obsbits; */ + /* dst->collection_loop_cnt= src->collection_loop_cnt; */ +} + + +/* + * Assessment of statistical behavior of the generated output and returning + * the information to the caller by filling the target value. + * + * Details about the bit statistics are given in chapter 4 of the doc. + * Chapter 5 documents the timer analysis and the resulting entropy. + */ +static void +jent_calc_statistic (struct rand_data *rand_data, + struct entropy_stat *target, unsigned int loop_cnt) +{ + /* int i; */ + /* struct entropy_stat *stat = &rand_data->entropy_stat; */ + + /* jent_get_nstime(&stat->collection_end); */ + + /* stat->collection_loop_cnt = loop_cnt; */ + + /* stat->setbits = 0; */ + /* stat->varbits = 0; */ + /* stat->obsbits = 0; */ + + /* for (i = 0; i < DATA_SIZE_BITS; i++) */ + /* { */ + /* stat->setbits += stat->bitslot[i]; */ + /* stat->varbits += stat->bitvar[i]; */ + + /* /\* This is the sum of set bits in the current observation */ + /* * of the random data. *\/ */ + /* stat->obsbits += (rand_data->data & 1<<i) ? 1:0; */ + /* } */ + + /* jent_statistic_copy_stat(stat, target); */ + + /* stat->old_delta = (stat->collection_end - stat->collection_begin); */ +} + +#endif /*CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT*/ + + +/* Acquire the jent_rng_lock. */ +static void +lock_rng (void) +{ + gpg_err_code_t rc; + + rc = gpgrt_lock_lock (&jent_rng_lock); + if (rc) + log_fatal ("failed to acquire the Jent RNG lock: %s\n", + gpg_strerror (rc)); + jent_rng_is_locked = 1; +} + + +/* Release the jent_rng_lock. */ +static void +unlock_rng (void) +{ + gpg_err_code_t rc; + + jent_rng_is_locked = 0; + rc = gpgrt_lock_unlock (&jent_rng_lock); + if (rc) + log_fatal ("failed to release the Jent RNG lock: %s\n", + gpg_strerror (rc)); +} + + +/* Return true if the JENT RNG code can be run. It may not yet been + * initialized, though. */ +static int +is_rng_available (void) +{ +#if USE_JENT == JENT_USES_RDTSC + return !!(_gcry_get_hw_features () & HWF_INTEL_RDTSC); +#elif USE_JENT == JENT_USES_GETTIME + return 2; +#elif USE_JENT == JENT_USES_READ_REAL_TIME + return 3; +#else /* Ooops */ + return 0; +#endif +} + +#endif /* USE_JENT */ + + +/* + * The API used by the high level code. + */ + +/* Read up to LENGTH bytes from a jitter RNG and return the number of + * bytes actually read. */ +size_t +_gcry_rndjent_poll (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin, size_t length) +{ + size_t nbytes = 0; + +#ifdef USE_JENT + if ( is_rng_available () ) + { + lock_rng (); + + if (!jent_rng_is_initialized) + { + /* Auto-initialize. */ + jent_rng_is_initialized = 1; + jent_entropy_collector_free (jent_rng_collector); + jent_rng_collector = NULL; + if ( !(_gcry_random_read_conf () & RANDOM_CONF_DISABLE_JENT)) + { + if (!jent_entropy_init ()) + jent_rng_collector = jent_entropy_collector_alloc (1, 0); + } + } + + if (jent_rng_collector && add) + { + /* We have a working JENT and it has not been disabled. */ + char buffer[32]; + + while (length) + { + int rc; + size_t n = length < sizeof(buffer)? length : sizeof (buffer); + + jent_rng_totalcalls++; + rc = jent_read_entropy (jent_rng_collector, buffer, n); + if (rc < 0) + break; + /* We need to hash the output to conform to the BSI + * NTG.1 specs. */ + _gcry_md_hash_buffer (GCRY_MD_SHA256, buffer, buffer, rc); + n = rc < 32? rc : 32; + (*add) (buffer, n, origin); + length -= n; + nbytes += n; + jent_rng_totalbytes += n; + } + wipememory (buffer, sizeof buffer); + } + + unlock_rng (); + } + +#else + + (void)add; + (void)origin; + +#endif + + return nbytes; +} + + +/* Return the version number of the JENT RNG. If the RNG is not + * initialized or usable 0 is returned. If R_ACTIVE is not NULL the + * jitter RNG will be initialized and true is stored at R_ACTIVE if + * the initialization succeeded. */ +unsigned int +_gcry_rndjent_get_version (int *r_active) +{ + if (r_active) + *r_active = 0; +#ifdef USE_JENT + if ( is_rng_available () ) + { + if (r_active) + { + /* Make sure the RNG is initialized. */ + _gcry_rndjent_poll (NULL, 0, 0); + + lock_rng (); + /* To ease debugging we store 2 for a clock_gettime based + * implementation and 1 for a rdtsc based code. */ + *r_active = jent_rng_collector? is_rng_available () : 0; + unlock_rng (); + } + return jent_version (); + } + else + return 0; +#else + return 0; +#endif +} + + +/* Log statistical informantion about the use of this module. */ +void +_gcry_rndjent_dump_stats (void) +{ + /* In theory we would need to lock the stats here. However this + * function is usually called during cleanup and then we _might_ run + * into problems. */ + +#ifdef USE_JENT + if ( is_rng_available () ) + { + log_info ("rndjent stat: collector=%p calls=%lu bytes=%lu\n", + jent_rng_collector, jent_rng_totalcalls, jent_rng_totalbytes); + + } +#endif /*USE_JENT*/ +} + + +void +_gcry_rndjent_fini (void) +{ +#ifdef USE_JENT + lock_rng (); + + if (jent_rng_is_initialized) + { + jent_entropy_collector_free (jent_rng_collector); + jent_rng_collector = NULL; + } + + unlock_rng (); +#endif +} diff --git a/comm/third_party/libgcrypt/random/rndlinux.c b/comm/third_party/libgcrypt/random/rndlinux.c new file mode 100644 index 0000000000..a7a78906d2 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndlinux.c @@ -0,0 +1,366 @@ +/* rndlinux.c - raw random number for OSes with /dev/random + * Copyright (C) 1998, 2001, 2002, 2003, 2007, + * 2009 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_GETTIMEOFDAY +# include <sys/times.h> +#endif +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#if defined(__APPLE__) && defined(__MACH__) +#include <Availability.h> +#ifdef __MAC_10_11 +extern int getentropy (void *buf, size_t buflen) __attribute__ ((weak_import)); +#define HAVE_GETENTROPY +#endif +#endif +#if defined(__linux__) || !defined(HAVE_GETENTROPY) +#ifdef HAVE_SYSCALL +# include <sys/syscall.h> +# ifdef __NR_getrandom +# define getentropy(buf,buflen) syscall (__NR_getrandom, buf, buflen, 0) +# endif +#endif +#endif + +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + +static int open_device (const char *name, int retry); + + +static int +set_cloexec_flag (int fd) +{ + int oldflags; + + oldflags= fcntl (fd, F_GETFD, 0); + if (oldflags < 0) + return oldflags; + oldflags |= FD_CLOEXEC; + return fcntl (fd, F_SETFD, oldflags); +} + + + +/* + * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it + * exists)). If RETRY is true, the function does not terminate with + * a fatal error but retries until it is able to reopen the device. + */ +static int +open_device (const char *name, int retry) +{ + int fd; + + if (retry) + _gcry_random_progress ("open_dev_random", 'X', 1, 0); + again: + fd = open (name, O_RDONLY); + if (fd == -1 && retry) + { + struct timeval tv; + + tv.tv_sec = 5; + tv.tv_usec = 0; + _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec); + select (0, NULL, NULL, NULL, &tv); + goto again; + } + if (fd == -1) + log_fatal ("can't open %s: %s\n", name, strerror(errno) ); + + if (set_cloexec_flag (fd)) + log_error ("error setting FD_CLOEXEC on fd %d: %s\n", + fd, strerror (errno)); + + /* We used to do the following check, however it turned out that this + is not portable since more OSes provide a random device which is + sometimes implemented as another device type. + + struct stat sb; + + if( fstat( fd, &sb ) ) + log_fatal("stat() off %s failed: %s\n", name, strerror(errno) ); + if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) ) + log_fatal("invalid random device!\n" ); + */ + return fd; +} + + +/* Note that the caller needs to make sure that this function is only + * called by one thread at a time. The function returns 0 on success + * or true on failure (in which case the caller will signal a fatal + * error). This function should be entered only by one thread at a + * time. */ +int +_gcry_rndlinux_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + static int fd_urandom = -1; + static int fd_random = -1; + static int only_urandom = -1; + static unsigned char ever_opened; + static volatile pid_t my_pid; /* The volatile is there to make sure + * the compiler does not optimize the + * code away in case the getpid + * function is badly attributed. */ + volatile pid_t apid; + int fd; + int n; + byte buffer[768]; + size_t n_hw; + size_t want = length; + size_t last_so_far = 0; + int any_need_entropy = 0; + int delay; + + /* On the first call read the conf file to check whether we want to + * use only urandom. */ + if (only_urandom == -1) + { + my_pid = getpid (); + if ((_gcry_random_read_conf () & RANDOM_CONF_ONLY_URANDOM)) + only_urandom = 1; + else + only_urandom = 0; + } + + if (!add) + { + /* Special mode to close the descriptors. */ + if (fd_random != -1) + { + close (fd_random); + fd_random = -1; + } + if (fd_urandom != -1) + { + close (fd_urandom); + fd_urandom = -1; + } + + _gcry_rndjent_fini (); + return 0; + } + + /* Detect a fork and close the devices so that we don't use the old + * file descriptors. Note that open_device will be called in retry + * mode if the devices was opened by the parent process. */ + apid = getpid (); + if (my_pid != apid) + { + if (fd_random != -1) + { + close (fd_random); + fd_random = -1; + } + if (fd_urandom != -1) + { + close (fd_urandom); + fd_urandom = -1; + } + my_pid = apid; + } + + + /* First read from a hardware source. Note that _gcry_rndhw_poll_slow lets + it account only for up to 50% (or 25% for RDRAND) of the requested + bytes. */ + n_hw = _gcry_rndhw_poll_slow (add, origin, length); + if (length > 1) + length -= n_hw; + + /* When using a blocking random generator try to get some entropy + * from the jitter based RNG. In this case we take up to 50% of the + * remaining requested bytes. */ + if (level >= GCRY_VERY_STRONG_RANDOM) + { + n_hw = _gcry_rndjent_poll (add, origin, length/2); + if (n_hw > length/2) + n_hw = length/2; + if (length > 1) + length -= n_hw; + } + + + /* Open the requested device. The first time a device is to be + opened we fail with a fatal error if the device does not exists. + In case the device has ever been closed, further open requests + will however retry indefinitely. The rationale for this behaviour is + that we always require the device to be existent but want a more + graceful behaviour if the rarely needed close operation has been + used and the device needs to be re-opened later. */ + if (level >= GCRY_VERY_STRONG_RANDOM && !only_urandom) + { + if (fd_random == -1) + { + fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1)); + ever_opened |= 1; + } + fd = fd_random; + } + else + { + if (fd_urandom == -1) + { + fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2)); + ever_opened |= 2; + } + fd = fd_urandom; + } + + /* Enter the read loop. */ + delay = 0; /* Start with 0 seconds so that we do no block on the + first iteration and in turn call the progress function + before blocking. To give the OS a better chance to + return with something we will actually use 100ms. */ + while (length) + { + fd_set rfds; + struct timeval tv; + int rc; + + /* If we have a modern operating system, we first try to use the new + * getentropy function. That call guarantees that the kernel's + * RNG has been properly seeded before returning any data. This + * is different from /dev/urandom which may, due to its + * non-blocking semantics, return data even if the kernel has + * not been properly seeded. And it differs from /dev/random by never + * blocking once the kernel is seeded. */ +#if defined(HAVE_GETENTROPY) || defined(__NR_getrandom) +#if defined(__APPLE__) && defined(__MACH__) + if (&getentropy != NULL) +#endif + { + long ret; + size_t nbytes; + + do + { + nbytes = length < sizeof(buffer)? length : sizeof(buffer); + if (nbytes > 256) + nbytes = 256; + _gcry_pre_syscall (); + ret = getentropy (buffer, nbytes); + _gcry_post_syscall (); + } + while (ret == -1 && errno == EINTR); + if (ret == -1 && errno == ENOSYS) + ; /* getentropy is not supported - fallback to pulling from fd. */ + else + { /* getentropy is supported. Some sanity checks. */ + if (ret == -1) + log_fatal ("unexpected error from getentropy: %s\n", + strerror (errno)); +#ifdef __NR_getrandom + else if (ret != nbytes) + log_fatal ("getentropy returned only" + " %ld of %zu requested bytes\n", ret, nbytes); +#endif + + (*add)(buffer, nbytes, origin); + length -= nbytes; + continue; /* until LENGTH is zero. */ + } + } +#endif + + /* If we collected some bytes update the progress indicator. We + do this always and not just if the select timed out because + often just a few bytes are gathered within the timeout + period. */ + if (any_need_entropy || last_so_far != (want - length) ) + { + last_so_far = want - length; + _gcry_random_progress ("need_entropy", 'X', + (int)last_so_far, (int)want); + any_need_entropy = 1; + } + + /* If the system has no limit on the number of file descriptors + and we encounter an fd which is larger than the fd_set size, + we don't use the select at all. The select code is only used + to emit progress messages. A better solution would be to + fall back to poll() if available. */ +#ifdef FD_SETSIZE + if (fd < FD_SETSIZE) +#endif + { + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = delay; + tv.tv_usec = delay? 0 : 100000; + _gcry_pre_syscall (); + rc = select (fd+1, &rfds, NULL, NULL, &tv); + _gcry_post_syscall (); + if (!rc) + { + any_need_entropy = 1; + delay = 3; /* Use 3 seconds henceforth. */ + continue; + } + else if( rc == -1 ) + { + log_error ("select() error: %s\n", strerror(errno)); + if (!delay) + delay = 1; /* Use 1 second if we encounter an error before + we have ever blocked. */ + continue; + } + } + + do + { + size_t nbytes; + + nbytes = length < sizeof(buffer)? length : sizeof(buffer); + n = read (fd, buffer, nbytes); + if (n >= 0 && n > nbytes) + { + log_error("bogus read from random device (n=%d)\n", n ); + n = nbytes; + } + } + while (n == -1 && errno == EINTR); + if (n == -1) + log_fatal("read error on random device: %s\n", strerror(errno)); + (*add)(buffer, n, origin); + length -= n; + } + wipememory (buffer, sizeof buffer); + + if (any_need_entropy) + _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want); + + return 0; /* success */ +} diff --git a/comm/third_party/libgcrypt/random/rndunix.c b/comm/third_party/libgcrypt/random/rndunix.c new file mode 100644 index 0000000000..aff2f85df5 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndunix.c @@ -0,0 +1,937 @@ +/**************************************************************************** + * * + * * + * Unix Randomness-Gathering Code * + * * + * Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1999. * + * Heavily modified for GnuPG by Werner Koch * + * * + * * + ****************************************************************************/ + +/* This module is part of the cryptlib continuously seeded pseudorandom + number generator. For usage conditions, see lib_rand.c + + [Here is the notice from lib_rand.c:] + + This module and the misc/rnd*.c modules represent the cryptlib + continuously seeded pseudorandom number generator (CSPRNG) as described in + my 1998 Usenix Security Symposium paper "The generation of random numbers + for cryptographic purposes". + + The CSPRNG code is copyright Peter Gutmann (and various others) 1996, + 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG + modules and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice + and this permission notice in its entirety. + + 2. Redistributions in binary form must reproduce the copyright notice in + the documentation and/or other materials provided with the distribution. + + 3. A copy of any bugfixes or enhancements made must be provided to the + author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the + baseline version of the code. + + ALTERNATIVELY, the code may be distributed under the terms of the + GNU Lesser General Public License, version 2.1 or any later version + published by the Free Software Foundation, in which case the + provisions of the GNU LGPL are required INSTEAD OF the above + restrictions. + + Although not required under the terms of the LGPL, it would still be + nice if you could make any changes available to the author to allow + a consistent code base to be maintained. */ +/************************************************************************* + The above alternative was changed from GPL to LGPL on 2007-08-22 with + permission from Peter Gutmann: + ========== + From: pgut001 <pgut001@cs.auckland.ac.nz> + Subject: Re: LGPL for the windows entropy gatherer + To: wk@gnupg.org + Date: Wed, 22 Aug 2007 03:05:42 +1200 + + Hi, + + >As of now libgcrypt is GPL under Windows due to that module and some people + >would really like to see it under LGPL too. Can you do such a license change + >to LGPL version 2? Note that LGPL give the user the option to relicense it + >under GPL, so the change would be pretty easy and backwar compatible. + + Sure. I assumed that since GPG was GPLd, you'd prefer the GPL for the entropy + code as well, but Ian asked for LGPL as an option so as of the next release + I'll have LGPL in there. You can consider it to be retroactive, so your + current version will be LGPLd as well. + + Peter. + ========== + From: pgut001 <pgut001@cs.auckland.ac.nz> + Subject: Re: LGPL for the windows entropy gatherer + To: wk@gnupg.org + Date: Wed, 22 Aug 2007 20:50:08 +1200 + + >Would you mind to extend this also to the Unix entropy gatherer which is + >still used on systems without /dev/random and when EGD is not installed? That + >would be the last GPLed piece in Libgcrypt. + + Sure, it covers the entire entropy-gathering subsystem. + + Peter. + ========= +*/ + +/* General includes */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#include <string.h> + +/* OS-specific includes */ + +#ifdef __osf__ + /* Somewhere in the morass of system-specific cruft which OSF/1 pulls in + * via the following includes are various endianness defines, so we + * undefine the cryptlib ones, which aren't really needed for this module + * anyway */ +#undef BIG_ENDIAN +#undef LITTLE_ENDIAN +#endif /* __osf__ */ + +#include <unistd.h> +#include <fcntl.h> +#include <pwd.h> +#ifndef __QNX__ +#include <sys/errno.h> +#include <sys/ipc.h> +#endif /* __QNX__ */ +#include <sys/time.h> /* SCO and SunOS need this before resource.h */ +#ifndef __QNX__ +#include <sys/resource.h> +#endif /* __QNX__ */ +#if defined( _AIX ) || defined( __QNX__ ) +#include <sys/select.h> +#endif /* _AIX */ +#ifndef __QNX__ +#include <sys/shm.h> +#include <signal.h> +#include <sys/signal.h> +#endif /* __QNX__ */ +#include <sys/stat.h> +#include <sys/types.h> /* Verschiedene komische Typen */ +#if defined( __hpux ) && ( OS_VERSION == 9 ) +#include <vfork.h> +#endif /* __hpux 9.x, after that it's in unistd.h */ +#include <sys/wait.h> +/* #include <kitchensink.h> */ +#ifdef __QNX__ +#include <signal.h> +#include <process.h> +#endif /* __QNX__ */ +#include <errno.h> + +#include "types.h" /* for byte and u32 typedefs */ +#include "g10lib.h" +#include "rand-internal.h" + +#ifndef EAGAIN +#define EAGAIN EWOULDBLOCK +#endif +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif + +#define GATHER_BUFSIZE 49152 /* Usually about 25K are filled */ + +/* The structure containing information on random-data sources. Each + * record contains the source and a relative estimate of its usefulness + * (weighting) which is used to scale the number of kB of output from the + * source (total = data_bytes / usefulness). Usually the weighting is in the + * range 1-3 (or 0 for especially useless sources), resulting in a usefulness + * rating of 1...3 for each kB of source output (or 0 for the useless + * sources). + * + * If the source is constantly changing (certain types of network statistics + * have this characteristic) but the amount of output is small, the weighting + * is given as a negative value to indicate that the output should be treated + * as if a minimum of 1K of output had been obtained. If the source produces + * a lot of output then the scale factor is fractional, resulting in a + * usefulness rating of < 1 for each kB of source output. + * + * In order to provide enough randomness to satisfy the requirements for a + * slow poll, we need to accumulate at least 20 points of usefulness (a + * typical system should get about 30 points). + * + * Some potential options are missed out because of special considerations. + * pstat -i and pstat -f can produce amazing amounts of output (the record + * is 600K on an Oracle server) which floods the buffer and doesn't yield + * anything useful (apart from perhaps increasing the entropy of the vmstat + * output a bit), so we don't bother with this. pstat in general produces + * quite a bit of output, but it doesn't change much over time, so it gets + * very low weightings. netstat -s produces constantly-changing output but + * also produces quite a bit of it, so it only gets a weighting of 2 rather + * than 3. The same holds for netstat -in, which gets 1 rather than 2. + * + * Some binaries are stored in different locations on different systems so + * alternative paths are given for them. The code sorts out which one to + * run by itself, once it finds an exectable somewhere it moves on to the + * next source. The sources are arranged roughly in their order of + * usefulness, occasionally sources which provide a tiny amount of + * relatively useless data are placed ahead of ones which provide a large + * amount of possibly useful data because another 100 bytes can't hurt, and + * it means the buffer won't be swamped by one or two high-output sources. + * All the high-output sources are clustered towards the end of the list + * for this reason. Some binaries are checked for in a certain order, for + * example under Slowaris /usr/ucb/ps understands aux as an arg, but the + * others don't. Some systems have conditional defines enabling alternatives + * to commands which don't understand the usual options but will provide + * enough output (in the form of error messages) to look like they're the + * real thing, causing alternative options to be skipped (we can't check the + * return either because some commands return peculiar, non-zero status even + * when they're working correctly). + * + * In order to maximise use of the buffer, the code performs a form of run- + * length compression on its input where a repeated sequence of bytes is + * replaced by the occurrence count mod 256. Some commands output an awful + * lot of whitespace, this measure greatly increases the amount of data we + * can fit in the buffer. + * + * When we scale the weighting using the SC() macro, some preprocessors may + * give a division by zero warning for the most obvious expression + * 'weight ? 1024 / weight : 0' (and gcc 2.7.2.2 dies with a division by zero + * trap), so we define a value SC_0 which evaluates to zero when fed to + * '1024 / SC_0' */ + +#define SC( weight ) ( 1024 / weight ) /* Scale factor */ +#define SC_0 16384 /* SC( SC_0 ) evaluates to 0 */ + +static struct RI { + const char *path; /* Path to check for existence of source */ + const char *arg; /* Args for source */ + const int usefulness; /* Usefulness of source */ + FILE *pipe; /* Pipe to source as FILE * */ + int pipeFD; /* Pipe to source as FD */ + pid_t pid; /* pid of child for waitpid() */ + int length; /* Quantity of output produced */ + const int hasAlternative; /* Whether source has alt.location */ +} dataSources[] = { + + { "/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 0}, + { "/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 0}, + { "/usr/bin/pfstat", NULL, SC(-2), NULL, 0, 0, 0, 0}, + { "/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 0}, + { "/usr/ucb/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1}, + { "/usr/etc/netstat", "-s", SC(2), NULL, 0, 0, 0, 0}, + { "/usr/bin/nfsstat", NULL, SC(2), NULL, 0, 0, 0, 0}, + { "/usr/ucb/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/etc/netstat", "-m", SC(-1), NULL, 0, 0, 0, 0 }, + { "/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/ucb/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1}, + { "/usr/etc/netstat", "-in", SC(-1), NULL, 0, 0, 0, 0}, + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.1.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* UDP in */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.4.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* UDP out */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.4.3.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* IP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.10.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.11.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.13.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/bin/mpstat", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/w", NULL, SC(1), NULL, 0, 0, 0, 1 }, + { "/usr/bsd/w", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/df", NULL, SC(1), NULL, 0, 0, 0, 1 }, + { "/bin/df", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/portstat", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/iostat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/usr/bin/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bsd/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/usr/ucb/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/etc/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 0 }, +#if defined( __sgi ) || defined( __hpux ) + { "/bin/ps", "-el", SC(0.3), NULL, 0, 0, 0, 1 }, +#endif /* __sgi || __hpux */ + { "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 }, + { "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 0 }, + { "/bin/ps", "-A", SC(0.3), NULL, 0, 0, 0, 0 }, /*QNX*/ + { "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 0 }, + /* Unreliable source, depends on system usage */ + { "/etc/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 }, + /* pstat is your friend */ + { "/usr/bin/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 1 }, +#ifdef __sgi + { "/usr/bsd/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 }, +#endif /* __sgi */ +#ifdef __hpux + { "/etc/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 }, +#endif /* __hpux */ + { "/usr/bsd/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.1.0", + SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.3.0", + SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */ + { "/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/ripquery", "-nw 1 127.0.0.1", + SC(0.1), NULL, 0, 0, 0, 0 }, + { "/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/ucb/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/tcpdump", "-c 5 -efvvx", SC(1), NULL, 0, 0, 0, 0 }, + /* This is very environment-dependent. If network traffic is low, it'll + * probably time out before delivering 5 packets, which is OK because + * it'll probably be fixed stuff like ARP anyway */ + { "/usr/sbin/advfsstat", "-b usr_domain", + SC(SC_0), NULL, 0, 0, 0, 0}, + { "/usr/sbin/advfsstat", "-l 2 usr_domain", + SC(0.5), NULL, 0, 0, 0, 0}, + { "/usr/sbin/advfsstat", "-p usr_domain", + SC(SC_0), NULL, 0, 0, 0, 0}, + /* This is a complex and screwball program. Some systems have things + * like rX_dmn, x = integer, for RAID systems, but the statistics are + * pretty dodgy */ +#ifdef __QNXNTO__ + { "/bin/pidin", "-F%A%B%c%d%E%I%J%K%m%M%n%N%p%P%S%s%T", SC(0.3), + NULL, 0, 0, 0, 0 }, +#endif +#if 0 + /* The following aren't enabled since they're somewhat slow and not very + * unpredictable, however they give an indication of the sort of sources + * you can use (for example the finger might be more useful on a + * firewalled internal network) */ + { "/usr/bin/finger", "@ml.media.mit.edu", SC(0.9), NULL, 0, 0, 0, 0 }, + { "/usr/local/bin/wget", "-O - http://lavarand.sgi.com/block.html", + SC(0.9), NULL, 0, 0, 0, 0 }, + { "/bin/cat", "/usr/spool/mqueue/syslog", SC(0.9), NULL, 0, 0, 0, 0 }, +#endif /* 0 */ + { NULL, NULL, 0, NULL, 0, 0, 0, 0 } +}; + +static byte *gather_buffer; /* buffer for gathering random noise */ +static int gather_buffer_size; /* size of the memory buffer */ +static uid_t gatherer_uid; + +/* The message structure used to communicate with the parent */ +typedef struct { + int usefulness; /* usefulness of data */ + int ndata; /* valid bytes in data */ + char data[500]; /* gathered data */ +} GATHER_MSG; + +#ifndef HAVE_WAITPID +static pid_t +waitpid(pid_t pid, int *statptr, int options) +{ +#ifdef HAVE_WAIT4 + return wait4(pid, statptr, options, NULL); +#else + /* If wait4 is also not available, try wait3 for SVR3 variants */ + /* Less ideal because can't actually request a specific pid */ + /* For that reason, first check to see if pid is for an */ + /* existing process. */ + int tmp_pid, dummystat;; + if (kill(pid, 0) == -1) { + errno = ECHILD; + return -1; + } + if (statptr == NULL) + statptr = &dummystat; + while (((tmp_pid = wait3(statptr, options, 0)) != pid) && + (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1)) + ; + return tmp_pid; +#endif +} +#endif + +/* Under SunOS popen() doesn't record the pid of the child process. When + * pclose() is called, instead of calling waitpid() for the correct child, it + * calls wait() repeatedly until the right child is reaped. The problem is + * that this reaps any other children that happen to have died at that + * moment, and when their pclose() comes along, the process hangs forever. + * The fix is to use a wrapper for popen()/pclose() which saves the pid in + * the dataSources structure (code adapted from GNU-libc's popen() call). + * + * Aut viam inveniam aut faciam */ + +static FILE * +my_popen(struct RI *entry) +{ + int pipedes[2]; + FILE *stream; + + /* Create the pipe */ + if (pipe(pipedes) < 0) + return (NULL); + + /* Fork off the child ("vfork() is like an OS orgasm. All OS's want to + * do it, but most just end up faking it" - Chris Wedgwood). If your OS + * supports it, you should try to use vfork() here because it's somewhat + * more efficient */ +#if defined( sun ) || defined( __ultrix__ ) || defined( __osf__ ) || \ + defined(__hpux) + entry->pid = vfork(); +#else /* */ + entry->pid = fork(); +#endif /* Unixen which have vfork() */ + if (entry->pid == (pid_t) - 1) { + /* The fork failed */ + close(pipedes[0]); + close(pipedes[1]); + return (NULL); + } + + if (entry->pid == (pid_t) 0) { + struct passwd *passwd; + + /* We are the child. Make the read side of the pipe be stdout */ + if (dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0) + exit(127); + + /* Now that everything is set up, give up our permissions to make + * sure we don't read anything sensitive. If the getpwnam() fails, + * we default to -1, which is usually nobody */ + if (gatherer_uid == (uid_t)-1 && \ + (passwd = getpwnam("nobody")) != NULL) + gatherer_uid = passwd->pw_uid; + + setuid(gatherer_uid); + + /* Close the pipe descriptors */ + close(pipedes[STDIN_FILENO]); + close(pipedes[STDOUT_FILENO]); + + /* Try and exec the program */ + execl(entry->path, entry->path, entry->arg, NULL); + + /* Die if the exec failed */ + exit(127); + } + + /* We are the parent. Close the irrelevant side of the pipe and open + * the relevant side as a new stream. Mark our side of the pipe to + * close on exec, so new children won't see it */ + close(pipedes[STDOUT_FILENO]); + +#ifdef FD_CLOEXEC + fcntl(pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC); +#endif + + stream = fdopen(pipedes[STDIN_FILENO], "r"); + + if (stream == NULL) { + int savedErrno = errno; + + /* The stream couldn't be opened or the child structure couldn't be + * allocated. Kill the child and close the other side of the pipe */ + kill(entry->pid, SIGKILL); + if (stream == NULL) + close(pipedes[STDOUT_FILENO]); + else + fclose(stream); + + waitpid(entry->pid, NULL, 0); + + entry->pid = 0; + errno = savedErrno; + return (NULL); + } + + return (stream); +} + +static int +my_pclose(struct RI *entry) +{ + int status = 0; + + if (fclose(entry->pipe)) + return (-1); + + /* We ignore the return value from the process because some + programs return funny values which would result in the input + being discarded even if they executed successfully. This isn't + a problem because the result data size threshold will filter + out any programs which exit with a usage message without + producing useful output. */ + if (waitpid(entry->pid, NULL, 0) != entry->pid) + status = -1; + + entry->pipe = NULL; + entry->pid = 0; + return (status); +} + + +/* Unix slow poll (without special support for Linux) + * + * If a few of the randomness sources create a large amount of output then + * the slowPoll() stops once the buffer has been filled (but before all the + * randomness sources have been sucked dry) so that the 'usefulness' factor + * remains below the threshold. For this reason the gatherer buffer has to + * be fairly sizeable on moderately loaded systems. This is something of a + * bug since the usefulness should be influenced by the amount of output as + * well as the source type */ + + +static int +slow_poll(FILE *dbgfp, int dbgall, size_t *nbytes ) +{ + int moreSources; + struct timeval tv; + fd_set fds; +#if defined( __hpux ) + size_t maxFD = 0; +#else + int maxFD = 0; +#endif /* OS-specific brokenness */ + int bufPos, i, usefulness = 0; + int last_so_far = 0; + int any_need_entropy = 0; + int delay; + int rc; + + /* Fire up each randomness source */ + FD_ZERO(&fds); + for (i = 0; dataSources[i].path != NULL; i++) { + /* Since popen() is a fairly heavy function, we check to see whether + * the executable exists before we try to run it */ + if (access(dataSources[i].path, X_OK)) { + if( dbgfp && dbgall ) + fprintf(dbgfp, "%s not present%s\n", dataSources[i].path, + dataSources[i].hasAlternative ? + ", has alternatives" : ""); + dataSources[i].pipe = NULL; + } + else + dataSources[i].pipe = my_popen(&dataSources[i]); + + if (dataSources[i].pipe != NULL) { + dataSources[i].pipeFD = fileno(dataSources[i].pipe); + if (dataSources[i].pipeFD > maxFD) + maxFD = dataSources[i].pipeFD; + +#ifdef O_NONBLOCK /* Ohhh what a hack (used for Atari) */ + fcntl(dataSources[i].pipeFD, F_SETFL, O_NONBLOCK); +#else +#error O_NONBLOCK is missing +#endif + /* FIXME: We need to make sure that the fd is less than + FD_SETSIZE. */ + FD_SET(dataSources[i].pipeFD, &fds); + dataSources[i].length = 0; + + /* If there are alternatives for this command, don't try and + * execute them */ + while (dataSources[i].hasAlternative) { + if( dbgfp && dbgall ) + fprintf(dbgfp, "Skipping %s\n", dataSources[i + 1].path); + i++; + } + } + } + + + /* Suck all the data we can get from each of the sources */ + bufPos = 0; + moreSources = 1; + delay = 0; /* Return immediately (well, after 100ms) the first time. */ + while (moreSources && bufPos <= gather_buffer_size) { + /* Wait for data to become available from any of the sources, with a + * timeout of 10 seconds. This adds even more randomness since data + * becomes available in a nondeterministic fashion. Kudos to HP's QA + * department for managing to ship a select() which breaks its own + * prototype */ + tv.tv_sec = delay; + tv.tv_usec = delay? 0 : 100000; + +#if defined( __hpux ) && ( OS_VERSION == 9 ) + rc = select(maxFD + 1, (int *)&fds, NULL, NULL, &tv); +#else /* */ + rc = select(maxFD + 1, &fds, NULL, NULL, &tv); +#endif /* __hpux */ + if (rc == -1) + break; /* Ooops; select failed. */ + + if (!rc) + { + /* FIXME: Because we run several tools at once it is + unlikely that we will see a block in select at all. */ + if (!any_need_entropy + || last_so_far != (gather_buffer_size - bufPos) ) + { + last_so_far = gather_buffer_size - bufPos; + _gcry_random_progress ("need_entropy", 'X', + last_so_far, + gather_buffer_size); + any_need_entropy = 1; + } + delay = 10; /* Use 10 seconds henceforth. */ + /* Note that the fd_set is setup again at the end of this loop. */ + } + + /* One of the sources has data available, read it into the buffer */ + for (i = 0; dataSources[i].path != NULL; i++) { + if( dataSources[i].pipe && FD_ISSET(dataSources[i].pipeFD, &fds)) { + size_t noBytes; + + if ((noBytes = fread(gather_buffer + bufPos, 1, + gather_buffer_size - bufPos, + dataSources[i].pipe)) == 0) { + if (my_pclose(&dataSources[i]) == 0) { + int total = 0; + + /* Try and estimate how much entropy we're getting + * from a data source */ + if (dataSources[i].usefulness) { + if (dataSources[i].usefulness < 0) + total = (dataSources[i].length + 999) + / -dataSources[i].usefulness; + else + total = dataSources[i].length + / dataSources[i].usefulness; + } + if( dbgfp ) + fprintf(dbgfp, + "%s %s contributed %d bytes, " + "usefulness = %d\n", dataSources[i].path, + (dataSources[i].arg != NULL) ? + dataSources[i].arg : "", + dataSources[i].length, total); + if( dataSources[i].length ) + usefulness += total; + } + dataSources[i].pipe = NULL; + } + else { + int currPos = bufPos; + int endPos = bufPos + noBytes; + + /* Run-length compress the input byte sequence */ + while (currPos < endPos) { + int ch = gather_buffer[currPos]; + + /* If it's a single byte, just copy it over */ + if (ch != gather_buffer[currPos + 1]) { + gather_buffer[bufPos++] = ch; + currPos++; + } + else { + int count = 0; + + /* It's a run of repeated bytes, replace them + * with the byte count mod 256 */ + while ((ch == gather_buffer[currPos]) + && currPos < endPos) { + count++; + currPos++; + } + gather_buffer[bufPos++] = count; + noBytes -= count - 1; + } + } + + /* Remember the number of (compressed) bytes of input we + * obtained */ + dataSources[i].length += noBytes; + } + } + } + + /* Check if there is more input available on any of the sources */ + moreSources = 0; + FD_ZERO(&fds); + for (i = 0; dataSources[i].path != NULL; i++) { + if (dataSources[i].pipe != NULL) { + FD_SET(dataSources[i].pipeFD, &fds); + moreSources = 1; + } + } + } + + if (any_need_entropy) + _gcry_random_progress ("need_entropy", 'X', + gather_buffer_size, + gather_buffer_size); + + if( dbgfp ) { + fprintf(dbgfp, "Got %d bytes, usefulness = %d\n", bufPos, usefulness); + fflush(dbgfp); + } + *nbytes = bufPos; + return usefulness; +} + +/**************** + * Start the gatherer process which writes messages of + * type GATHERER_MSG to pipedes + */ +static void +start_gatherer( int pipefd ) +{ + FILE *dbgfp = NULL; + int dbgall; + + { + const char *s = getenv("GCRYPT_RNDUNIX_DBG"); + if( s ) { + dbgfp = (*s=='-' && !s[1])? stdout : fopen(s, "a"); + if( !dbgfp ) + log_info("can't open debug file `%s': %s\n", + s, strerror(errno) ); + else + fprintf(dbgfp,"\nSTART RNDUNIX DEBUG pid=%d\n", (int)getpid()); + } + dbgall = !!getenv("GCRYPT_RNDUNIX_DBGALL"); + } + /* close all files but the ones we need */ + { int nmax, n1, n2, i; +#ifdef _SC_OPEN_MAX + if( (nmax=sysconf( _SC_OPEN_MAX )) < 0 ) { +# ifdef _POSIX_OPEN_MAX + nmax = _POSIX_OPEN_MAX; +# else + nmax = 20; /* assume a reasonable value */ +# endif + } + /* AIX returns INT32_MAX instead of a proper value. We assume that + * this is always an error and use a reasonable value. */ +# ifdef INT32_MAX + if (nmax == INT32_MAX) + nmax = 20; +# endif +#else /*!_SC_OPEN_MAX*/ + nmax = 20; /* assume a reasonable value */ +#endif /*!_SC_OPEN_MAX*/ + n1 = fileno( stderr ); + n2 = dbgfp? fileno( dbgfp ) : -1; + for(i=0; i < nmax; i++ ) { + if( i != n1 && i != n2 && i != pipefd ) + close(i); + } + errno = 0; + } + + + /* Set up the buffer. Not ethat we use a plain standard malloc here. */ + gather_buffer_size = GATHER_BUFSIZE; + gather_buffer = malloc( gather_buffer_size ); + if( !gather_buffer ) { + log_error("out of core while allocating the gatherer buffer\n"); + exit(2); + } + + /* Reset the SIGC(H)LD handler to the system default. This is necessary + * because if the program which cryptlib is a part of installs its own + * SIGC(H)LD handler, it will end up reaping the cryptlib children before + * cryptlib can. As a result, my_pclose() will call waitpid() on a + * process which has already been reaped by the installed handler and + * return an error, so the read data won't be added to the randomness + * pool. There are two types of SIGC(H)LD naming, the SysV SIGCLD and + * the BSD/Posix SIGCHLD, so we need to handle either possibility */ +#ifdef SIGCLD + signal(SIGCLD, SIG_DFL); +#else + signal(SIGCHLD, SIG_DFL); +#endif + + fclose(stderr); /* Arrghh!! It's Stuart code!! */ + + /* Mary goes to Berkeley: NetBSD emits warnings if the standard + descriptors are not open when running setuid program. Thus we + connect them to the bitbucket if they are not already open. */ + { + struct stat statbuf; + + if (fstat (STDIN_FILENO, &statbuf) == -1 && errno == EBADF) + open ("/dev/null",O_RDONLY); + if (fstat (STDOUT_FILENO, &statbuf) == -1 && errno == EBADF) + open ("/dev/null",O_WRONLY); + if (fstat (STDERR_FILENO, &statbuf) == -1 && errno == EBADF) + open ("/dev/null",O_WRONLY); + } + + for(;;) { + GATHER_MSG msg; + size_t nbytes; + const char *p; + + msg.usefulness = slow_poll( dbgfp, dbgall, &nbytes ); + p = (const char*)gather_buffer; + while( nbytes ) { + msg.ndata = nbytes > sizeof(msg.data)? sizeof(msg.data) : nbytes; + memcpy( msg.data, p, msg.ndata ); + nbytes -= msg.ndata; + p += msg.ndata; + + while( write( pipefd, &msg, sizeof(msg) ) != sizeof(msg) ) { + if( errno == EINTR ) + continue; + if( errno == EAGAIN ) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 50000; + select(0, NULL, NULL, NULL, &tv); + continue; + } + if( errno == EPIPE ) /* parent has exited, so give up */ + exit(0); + + /* we can't do very much here because stderr is closed */ + if( dbgfp ) + fprintf(dbgfp, "gatherer can't write to pipe: %s\n", + strerror(errno) ); + /* we start a new poll to give the system some time */ + nbytes = 0; + break; + } + } + } + /* we are killed when the parent dies */ +} + + +static int +read_a_msg( int fd, GATHER_MSG *msg ) +{ + char *buffer = (char*)msg; + size_t length = sizeof( *msg ); + int n; + + do { + do { + n = read(fd, buffer, length ); + } while( n == -1 && errno == EINTR ); + if( n == -1 ) + return -1; + buffer += n; + length -= n; + } while( length ); + return 0; +} + + +/**************** + * Using a level of 0 should never block and better add nothing + * to the pool. So this is just a dummy for this gatherer. + */ +int +_gcry_rndunix_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + static pid_t gatherer_pid = 0; + static int pipedes[2]; + GATHER_MSG msg; + size_t n; + + if( !level ) + return 0; + + if( !gatherer_pid ) { + /* Make sure we are not setuid. */ + if ( getuid() != geteuid() ) + BUG(); + /* time to start the gatherer process */ + if( pipe( pipedes ) ) { + log_error("pipe() failed: %s\n", strerror(errno)); + return -1; + } + gatherer_pid = fork(); + if( gatherer_pid == -1 ) { + log_error("can't for gatherer process: %s\n", strerror(errno)); + return -1; + } + if( !gatherer_pid ) { + start_gatherer( pipedes[1] ); + /* oops, can't happen */ + return -1; + } + } + + /* now read from the gatherer */ + while( length ) { + int goodness; + unsigned long subtract; + + if( read_a_msg( pipedes[0], &msg ) ) { + log_error("reading from gatherer pipe failed: %s\n", + strerror(errno)); + return -1; + } + + + if( level > 1 ) { + if( msg.usefulness > 30 ) + goodness = 100; + else if ( msg.usefulness ) + goodness = msg.usefulness * 100 / 30; + else + goodness = 0; + } + else if( level ) { + if( msg.usefulness > 15 ) + goodness = 100; + else if ( msg.usefulness ) + goodness = msg.usefulness * 100 / 15; + else + goodness = 0; + } + else + goodness = 100; /* goodness of level 0 is always 100 % */ + + n = msg.ndata; + if( n > length ) + n = length; + (*add)( msg.data, n, origin ); + + /* this is the trick how we cope with the goodness */ + subtract = (unsigned long)n * goodness / 100; + /* subtract at least 1 byte to avoid infinite loops */ + length -= subtract ? subtract : 1; + } + + return 0; +} diff --git a/comm/third_party/libgcrypt/random/rndw32.c b/comm/third_party/libgcrypt/random/rndw32.c new file mode 100644 index 0000000000..b3f63d2072 --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndw32.c @@ -0,0 +1,1030 @@ +/* rndw32.c - W32 entropy gatherer + * Copyright (C) 1999, 2000, 2002, 2003, 2007, + * 2010 Free Software Foundation, Inc. + * Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-2006 + * + * This file is part of Libgcrypt. + * + ************************************************************************* + * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann. + * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this + * copyright notice: + * + * This module is part of the cryptlib continuously seeded pseudorandom + * number generator. For usage conditions, see lib_rand.c + * + * [Here is the notice from lib_rand.c, which is now called dev_sys.c] + * + * This module and the misc/rnd*.c modules represent the cryptlib + * continuously seeded pseudorandom number generator (CSPRNG) as described in + * my 1998 Usenix Security Symposium paper "The generation of random numbers + * for cryptographic purposes". + * + * The CSPRNG code is copyright Peter Gutmann (and various others) 1996, + * 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG + * modules and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice + * and this permission notice in its entirety. + * + * 2. Redistributions in binary form must reproduce the copyright notice in + * the documentation and/or other materials provided with the distribution. + * + * 3. A copy of any bugfixes or enhancements made must be provided to the + * author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the + * baseline version of the code. + * + * ALTERNATIVELY, the code may be distributed under the terms of the + * GNU Lesser General Public License, version 2.1 or any later version + * published by the Free Software Foundation, in which case the + * provisions of the GNU LGPL are required INSTEAD OF the above + * restrictions. + * + * Although not required under the terms of the LGPL, it would still + * be nice if you could make any changes available to the author to + * allow a consistent code base to be maintained. + ************************************************************************* + * The above alternative was changed from GPL to LGPL on 2007-08-22 with + * permission from Peter Gutmann: + *========== + From: pgut001 <pgut001@cs.auckland.ac.nz> + Subject: Re: LGPL for the windows entropy gatherer + To: wk@gnupg.org + Date: Wed, 22 Aug 2007 03:05:42 +1200 + + Hi, + + >As of now libgcrypt is GPL under Windows due to that module and some people + >would really like to see it under LGPL too. Can you do such a license change + >to LGPL version 2? Note that LGPL give the user the option to relicense it + >under GPL, so the change would be pretty easy and backwar compatible. + + Sure. I assumed that since GPG was GPLd, you'd prefer the GPL for the entropy + code as well, but Ian asked for LGPL as an option so as of the next release + I'll have LGPL in there. You can consider it to be retroactive, so your + current version will be LGPLd as well. + + Peter. + *========== + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#ifdef __GNUC__ +#include <stdint.h> +#endif + +#include <winsock2.h> +#include <windows.h> + + +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + + +/* Definitions which are missing from the current GNU Windows32Api. */ +#ifndef IOCTL_DISK_PERFORMANCE +#define IOCTL_DISK_PERFORMANCE 0x00070020 +#endif + +/* This used to be (6*8+5*4+8*2), but Peter Gutmann figured a larger + value in a newer release. So we use a far larger value. */ +#define SIZEOF_DISK_PERFORMANCE_STRUCT 256 + +/* We don't include wincrypt.h so define it here. */ +#define HCRYPTPROV HANDLE + + +/* When we query the performance counters, we allocate an initial buffer and + * then reallocate it as required until RegQueryValueEx() stops returning + * ERROR_MORE_DATA. The following values define the initial buffer size and + * step size by which the buffer is increased + */ +#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */ +#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */ + + +/* The number of bytes to read from the system RNG on each slow poll. */ +#define SYSTEMRNG_BYTES 64 + +/* Intel Chipset CSP type and name */ +#define PROV_INTEL_SEC 22 +#define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider" + + + + +/* Type definitions for function pointers to call NetAPI32 functions. */ +typedef DWORD (WINAPI *NETSTATISTICSGET)(LPWSTR szServer, LPWSTR szService, + DWORD dwLevel, DWORD dwOptions, + LPBYTE *lpBuffer); +typedef DWORD (WINAPI *NETAPIBUFFERSIZE)(LPVOID lpBuffer, LPDWORD cbBuffer); +typedef DWORD (WINAPI *NETAPIBUFFERFREE)(LPVOID lpBuffer); + +/* Type definitions for function pointers to call native NT functions. */ +typedef DWORD (WINAPI *NTQUERYSYSTEMINFORMATION)(DWORD systemInformationClass, + PVOID systemInformation, + ULONG systemInformationLength, + PULONG returnLength); +typedef DWORD (WINAPI *NTQUERYINFORMATIONPROCESS) + (HANDLE processHandle, DWORD processInformationClass, + PVOID processInformation, ULONG processInformationLength, + PULONG returnLength); +typedef DWORD (WINAPI *NTPOWERINFORMATION) + (DWORD powerInformationClass, PVOID inputBuffer, + ULONG inputBufferLength, PVOID outputBuffer, ULONG outputBufferLength ); + +/* Type definitions for function pointers to call CryptoAPI functions. */ +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV *phProv, + LPCTSTR pszContainer, + LPCTSTR pszProvider, + DWORD dwProvType, + DWORD dwFlags); +typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, + BYTE *pbBuffer); +typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); + +/* Somewhat alternative functionality available as a direct call, for + Windows XP and newer. This is the CryptoAPI RNG, which isn't anywhere + near as good as the HW RNG, but we use it if it's present on the basis + that at least it can't make things any worse. This direct access version + is only available under Windows XP, we don't go out of our way to access + the more general CryptoAPI one since the main purpose of using it is to + take advantage of any possible future hardware RNGs that may be added, + for example via TCPA devices. */ +typedef BOOL (WINAPI *RTLGENRANDOM)(PVOID RandomBuffer, + ULONG RandomBufferLength); + + + +/* MBM data structures, originally by Alexander van Kaam, converted to C by + Anders@Majland.org, finally updated by Chris Zahrt <techn0@iastate.edu> */ +#define BusType char +#define SMBType char +#define SensorType char + +typedef struct +{ + SensorType iType; /* Type of sensor. */ + int Count; /* Number of sensor for that type. */ +} SharedIndex; + +typedef struct +{ + SensorType ssType; /* Type of sensor */ + unsigned char ssName[12]; /* Name of sensor */ + char sspadding1[3]; /* Padding of 3 bytes */ + double ssCurrent; /* Current value */ + double ssLow; /* Lowest readout */ + double ssHigh; /* Highest readout */ + long ssCount; /* Total number of readout */ + char sspadding2[4]; /* Padding of 4 bytes */ + long double ssTotal; /* Total amount of all readouts */ + char sspadding3[6]; /* Padding of 6 bytes */ + double ssAlarm1; /* Temp & fan: high alarm; voltage: % off */ + double ssAlarm2; /* Temp: low alarm */ +} SharedSensor; + +typedef struct +{ + short siSMB_Base; /* SMBus base address */ + BusType siSMB_Type; /* SMBus/Isa bus used to access chip */ + SMBType siSMB_Code; /* SMBus sub type, Intel, AMD or ALi */ + char siSMB_Addr; /* Address of sensor chip on SMBus */ + unsigned char siSMB_Name[41]; /* Nice name for SMBus */ + short siISA_Base; /* ISA base address of sensor chip on ISA */ + int siChipType; /* Chip nr, connects with Chipinfo.ini */ + char siVoltageSubType; /* Subvoltage option selected */ +} SharedInfo; + +typedef struct +{ + double sdVersion; /* Version number (example: 51090) */ + SharedIndex sdIndex[10]; /* Sensor index */ + SharedSensor sdSensor[100]; /* Sensor info */ + SharedInfo sdInfo; /* Misc.info */ + unsigned char sdStart[41]; /* Start time */ + + /* We don't use the next two fields both because they're not random + and because it provides a nice safety margin in case of data size + mis- estimates (we always under-estimate the buffer size). */ +#if 0 + unsigned char sdCurrent[41]; /* Current time */ + unsigned char sdPath[256]; /* MBM path */ +#endif /*0*/ +} SharedData; + + + +/* One time initialized handles and function pointers. We use dynamic + loading of the DLLs to do without them in case libgcrypt does not + need any random. */ +static HANDLE hNetAPI32; +static NETSTATISTICSGET pNetStatisticsGet; +static NETAPIBUFFERSIZE pNetApiBufferSize; +static NETAPIBUFFERFREE pNetApiBufferFree; + +static HANDLE hNTAPI; +static NTQUERYSYSTEMINFORMATION pNtQuerySystemInformation; +static NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess; +static NTPOWERINFORMATION pNtPowerInformation; + +static HANDLE hAdvAPI32; +static CRYPTACQUIRECONTEXT pCryptAcquireContext; +static CRYPTGENRANDOM pCryptGenRandom; +static CRYPTRELEASECONTEXT pCryptReleaseContext; +static RTLGENRANDOM pRtlGenRandom; + + +/* Other module global variables. */ +static int system_rng_available; /* Whether a system RNG is available. */ +static HCRYPTPROV hRNGProv; /* Handle to Intel RNG CSP. */ + +/* The debug flag. Debugging is enabled if the value of the envvar + * GCRY_RNDW32_DBG is a positive number.*/ +static int debug_me; + +static int system_is_w2000; /* True if running on W2000. */ + + + +/* Try and connect to the system RNG if there's one present. */ +static void +init_system_rng (void) +{ + system_rng_available = 0; + hRNGProv = NULL; + + hAdvAPI32 = GetModuleHandle ("AdvAPI32.dll"); + if (!hAdvAPI32) + return; + + pCryptAcquireContext = (CRYPTACQUIRECONTEXT) + GetProcAddress (hAdvAPI32, "CryptAcquireContextA"); + pCryptGenRandom = (CRYPTGENRANDOM) + GetProcAddress (hAdvAPI32, "CryptGenRandom"); + pCryptReleaseContext = (CRYPTRELEASECONTEXT) + GetProcAddress (hAdvAPI32, "CryptReleaseContext"); + + /* Get a pointer to the native randomness function if it's available. + This isn't exported by name, so we have to get it by ordinal. */ + pRtlGenRandom = (RTLGENRANDOM) + GetProcAddress (hAdvAPI32, "SystemFunction036"); + + /* Try and connect to the PIII RNG CSP. The AMD 768 southbridge (from + the 760 MP chipset) also has a hardware RNG, but there doesn't appear + to be any driver support for this as there is for the Intel RNG so we + can't do much with it. OTOH the Intel RNG is also effectively dead + as well, mostly due to virtually nonexistent support/marketing by + Intel, it's included here mostly for form's sake. */ + if ( (!pCryptAcquireContext || !pCryptGenRandom || !pCryptReleaseContext + || !pCryptAcquireContext (&hRNGProv, NULL, INTEL_DEF_PROV, + PROV_INTEL_SEC, 0) ) + && !pRtlGenRandom) + { + hAdvAPI32 = NULL; + } + else + system_rng_available = 1; +} + + +/* Read data from the system RNG if availavle. */ +static void +read_system_rng (void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester) +{ + BYTE buffer[ SYSTEMRNG_BYTES + 8 ]; + int quality = 0; + + if (!system_rng_available) + return; + + /* Read SYSTEMRNG_BYTES bytes from the system RNG. We don't rely on + this for all our randomness requirements (particularly the + software RNG) in case it's broken in some way. */ + if (hRNGProv) + { + if (pCryptGenRandom (hRNGProv, SYSTEMRNG_BYTES, buffer)) + quality = 80; + } + else if (pRtlGenRandom) + { + if ( pRtlGenRandom (buffer, SYSTEMRNG_BYTES)) + quality = 50; + } + if (quality > 0) + { + if (debug_me) + log_debug ("rndw32#read_system_rng: got %d bytes of quality %d\n", + SYSTEMRNG_BYTES, quality); + (*add) (buffer, SYSTEMRNG_BYTES, requester); + wipememory (buffer, SYSTEMRNG_BYTES); + } +} + + +/* Read data from MBM. This communicates via shared memory, so all we + need to do is map a file and read the data out. */ +static void +read_mbm_data (void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester) +{ + HANDLE hMBMData; + SharedData *mbmDataPtr; + + hMBMData = OpenFileMapping (FILE_MAP_READ, FALSE, "$M$B$M$5$S$D$" ); + if (hMBMData) + { + mbmDataPtr = (SharedData*)MapViewOfFile (hMBMData, FILE_MAP_READ,0,0,0); + if (mbmDataPtr) + { + if (debug_me) + log_debug ("rndw32#read_mbm_data: got %d bytes\n", + (int)sizeof (SharedData)); + (*add) (mbmDataPtr, sizeof (SharedData), requester); + UnmapViewOfFile (mbmDataPtr); + } + CloseHandle (hMBMData); + } +} + + +/* Fallback method using the registry to poll the statistics. */ +static void +registry_poll (void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester) +{ + static int cbPerfData = PERFORMANCE_BUFFER_SIZE; + int iterations; + DWORD dwSize, status; + PERF_DATA_BLOCK *pPerfData; + + /* Get information from the system performance counters. This can take a + few seconds to do. In some environments the call to RegQueryValueEx() + can produce an access violation at some random time in the future, in + some cases adding a short delay after the following code block makes + the problem go away. This problem is extremely difficult to + reproduce, I haven't been able to get it to occur despite running it + on a number of machines. MS knowledge base article Q178887 covers + this type of problem, it's typically caused by an external driver or + other program that adds its own values under the + HKEY_PERFORMANCE_DATA key. The NT kernel, via Advapi32.dll, calls the + required external module to map in the data inside an SEH try/except + block, so problems in the module's collect function don't pop up until + after it has finished, so the fault appears to occur in Advapi32.dll. + There may be problems in the NT kernel as well though, a low-level + memory checker indicated that ExpandEnvironmentStrings() in + Kernel32.dll, called an interminable number of calls down inside + RegQueryValueEx(), was overwriting memory (it wrote twice the + allocated size of a buffer to a buffer allocated by the NT kernel). + OTOH this could be coming from the external module calling back into + the kernel, which eventually causes the problem described above. + + Possibly as an extension of the problem that the krnlWaitSemaphore() + call above works around, running two instances of cryptlib (e.g. two + applications that use it) under NT4 can result in one of them hanging + in the RegQueryValueEx() call. This happens only under NT4 and is + hard to reproduce in any consistent manner. + + One workaround that helps a bit is to read the registry as a remote + (rather than local) registry, it's possible that the use of a network + RPC call isolates the calling app from the problem in that whatever + service handles the RPC is taking the hit and not affecting the + calling app. Since this would require another round of extensive + testing to verify and the NT native API call is working fine, we'll + stick with the native API call for now. + + Some versions of NT4 had a problem where the amount of data returned + was mis-reported and would never settle down, because of this the code + below includes a safety-catch that bails out after 10 attempts have + been made, this results in no data being returned but at does ensure + that the thread will terminate. + + In addition to these problems the code in RegQueryValueEx() that + estimates the amount of memory required to return the performance + counter information isn't very accurate (it's much worse than the + "slightly-inaccurate" level that the MS docs warn about, it's usually + wildly off) since it always returns a worst-case estimate which is + usually nowhere near the actual amount required. For example it may + report that 128K of memory is required, but only return 64K of data. + + Even worse than the registry-based performance counters is the + performance data helper (PDH) shim that tries to make the counters + look like the old Win16 API (which is also used by Win95). Under NT + this can consume tens of MB of memory and huge amounts of CPU time + while it gathers its data, and even running once can still consume + about 1/2MB of memory */ + if (getenv ("GCRYPT_RNDW32_NOPERF")) + { + static int shown; + + if (!shown) + { + shown = 1; + log_info ("note: get performance data has been disabled\n"); + } + } + else + { + pPerfData = xmalloc (cbPerfData); + for (iterations=0; iterations < 10; iterations++) + { + dwSize = cbPerfData; + if ( debug_me ) + log_debug ("rndw32#slow_gatherer_nt: get perf data\n" ); + + status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL, + NULL, (LPBYTE) pPerfData, &dwSize); + if (status == ERROR_SUCCESS) + { + if (!memcmp (pPerfData->Signature, L"PERF", 8)) + (*add) ( pPerfData, dwSize, requester ); + else + log_debug ("rndw32: no PERF signature\n"); + break; + } + else if (status == ERROR_MORE_DATA) + { + cbPerfData += PERFORMANCE_BUFFER_STEP; + pPerfData = xrealloc (pPerfData, cbPerfData); + } + else + { + static int been_here; + + /* Silence the error message. In particular under Wine (as + of 2008) we would get swamped with such diagnotiscs. One + such diagnotiscs should be enough. */ + if (been_here != status) + { + been_here = status; + log_debug ("rndw32: get performance data problem: ec=%ld\n", + status); + } + break; + } + } + xfree (pPerfData); + } + + /* Although this isn't documented in the Win32 API docs, it's necessary + to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's + implicitly opened on the first call to RegQueryValueEx()). If this + isn't done then any system components which provide performance data + can't be removed or changed while the handle remains active. */ + RegCloseKey (HKEY_PERFORMANCE_DATA); +} + + +static void +slow_gatherer ( void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester ) +{ + static int is_initialized = 0; + static int is_workstation = 1; + HANDLE hDevice; + DWORD dwType, dwSize, dwResult; + ULONG ulSize; + int drive_no, status; + int no_results = 0; + void *buffer; + + if ( !is_initialized ) + { + HKEY hKey; + + if ( debug_me ) + log_debug ("rndw32#slow_gatherer: init toolkit\n" ); + /* Find out whether this is an NT server or workstation if necessary */ + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + BYTE szValue[32 + 8]; + dwSize = 32; + + if ( debug_me ) + log_debug ("rndw32#slow_gatherer: check product options\n" ); + + status = RegQueryValueEx (hKey, "ProductType", 0, NULL, + szValue, &dwSize); + if (status == ERROR_SUCCESS && stricmp ((char*)szValue, "WinNT")) + { + /* Note: There are (at least) three cases for ProductType: + WinNT = NT Workstation, ServerNT = NT Server, LanmanNT = + NT Server acting as a Domain Controller. */ + is_workstation = 0; + if ( debug_me ) + log_debug ("rndw32: this is a NT server\n"); + } + RegCloseKey (hKey); + } + + /* The following are fixed for the lifetime of the process so we + only add them once */ + /* readPnPData (); - we have not implemented that. */ + + /* Initialize the NetAPI32 function pointers if necessary */ + hNetAPI32 = LoadLibrary ("NETAPI32.DLL"); + if (hNetAPI32) + { + if (debug_me) + log_debug ("rndw32#slow_gatherer: netapi32 loaded\n" ); + pNetStatisticsGet = (NETSTATISTICSGET) + GetProcAddress (hNetAPI32, "NetStatisticsGet"); + pNetApiBufferSize = (NETAPIBUFFERSIZE) + GetProcAddress (hNetAPI32, "NetApiBufferSize"); + pNetApiBufferFree = (NETAPIBUFFERFREE) + GetProcAddress (hNetAPI32, "NetApiBufferFree"); + + if (!pNetStatisticsGet || !pNetApiBufferSize || !pNetApiBufferFree) + { + FreeLibrary (hNetAPI32); + hNetAPI32 = NULL; + log_debug ("rndw32: No NETAPI found\n" ); + } + } + + /* Initialize the NT kernel native API function pointers if necessary */ + hNTAPI = GetModuleHandle ("NTDll.dll"); + if (hNTAPI) + { + /* Get a pointer to the NT native information query functions */ + pNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION) + GetProcAddress (hNTAPI, "NtQuerySystemInformation"); + pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS) + GetProcAddress (hNTAPI, "NtQueryInformationProcess"); + pNtPowerInformation = (NTPOWERINFORMATION) + GetProcAddress(hNTAPI, "NtPowerInformation"); + + if (!pNtQuerySystemInformation || !pNtQueryInformationProcess) + hNTAPI = NULL; + } + + + is_initialized = 1; + } + + read_system_rng ( add, requester ); + read_mbm_data ( add, requester ); + + /* Get network statistics. Note: Both NT Workstation and NT Server by + default will be running both the workstation and server services. The + heuristic below is probably useful though on the assumption that the + majority of the network traffic will be via the appropriate service. + In any case the network statistics return almost no randomness. */ + { + LPBYTE lpBuffer; + + if (hNetAPI32 + && !pNetStatisticsGet (NULL, + (LPWSTR)(is_workstation ? L"LanmanWorkstation" : + L"LanmanServer"), 0, 0, &lpBuffer)) + { + if ( debug_me ) + log_debug ("rndw32#slow_gatherer: get netstats\n" ); + pNetApiBufferSize (lpBuffer, &dwSize); + (*add) ( lpBuffer, dwSize, requester ); + pNetApiBufferFree (lpBuffer); + } + } + + /* Get disk I/O statistics for all the hard drives. 100 is an + arbitrary failsafe limit. */ + for (drive_no = 0; drive_no < 100 ; drive_no++) + { + char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT + 8]; + char szDevice[50]; + + /* Check whether we can access this device. */ + snprintf (szDevice, sizeof szDevice, "\\\\.\\PhysicalDrive%d", + drive_no); + hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (hDevice == INVALID_HANDLE_VALUE) + break; /* No more drives. */ + + /* Note: This only works if you have turned on the disk performance + counters with 'diskperf -y'. These counters are off by default. */ + dwSize = sizeof diskPerformance; + if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, + diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT, + &dwSize, NULL)) + { + if ( debug_me ) + log_debug ("rndw32#slow_gatherer: iostat drive %d\n", + drive_no); + (*add) (diskPerformance, dwSize, requester); + } + else + { + log_info ("NOTE: you should run 'diskperf -y' " + "to enable the disk statistics\n"); + } + CloseHandle (hDevice); + } + + /* In theory we should be using the Win32 performance query API to obtain + unpredictable data from the system, however this is so unreliable (see + the multiple sets of comments in registryPoll()) that it's too risky + to rely on it except as a fallback in emergencies. Instead, we rely + mostly on the NT native API function NtQuerySystemInformation(), which + has the dual advantages that it doesn't have as many (known) problems + as the Win32 equivalent and that it doesn't access the data indirectly + via pseudo-registry keys, which means that it's much faster. Note + that the Win32 equivalent actually works almost all of the time, the + problem is that on one or two systems it can fail in strange ways that + are never the same and can't be reproduced on any other system, which + is why we use the native API here. Microsoft officially documented + this function in early 2003, so it'll be fairly safe to use. */ + if ( !hNTAPI ) + { + registry_poll (add, requester); + return; + } + + + /* Scan the first 64 possible information types (we don't bother with + increasing the buffer size as we do with the Win32 version of the + performance data read, we may miss a few classes but it's no big deal). + This scan typically yields around 20 pieces of data, there's nothing + in the range 65...128 so chances are there won't be anything above + there either. */ + buffer = xmalloc (PERFORMANCE_BUFFER_SIZE); + for (dwType = 0; dwType < 64; dwType++) + { + switch (dwType) + { + /* ID 17 = SystemObjectInformation hangs on some win2k systems. */ + case 17: + if (system_is_w2000) + continue; + break; + + /* Some information types are write-only (the IDs are shared with + a set-information call), we skip these. */ + case 26: case 27: case 38: case 46: case 47: case 48: case 52: + continue; + + /* ID 53 = SystemSessionProcessInformation reads input from the + output buffer, which has to contain a session ID and pointer + to the actual buffer in which to store the session information. + Because this isn't a standard query, we skip this. */ + case 53: + continue; + } + + /* Query the info for this ID. Some results (for example for + ID = 6, SystemCallCounts) are only available in checked builds + of the kernel. A smaller subcless of results require that + certain system config flags be set, for example + SystemObjectInformation requires that the + FLG_MAINTAIN_OBJECT_TYPELIST be set in NtGlobalFlags. To avoid + having to special-case all of these, we try reading each one and + only use those for which we get a success status. */ + dwResult = pNtQuerySystemInformation (dwType, buffer, + PERFORMANCE_BUFFER_SIZE - 2048, + &ulSize); + if (dwResult != ERROR_SUCCESS) + continue; + + /* Some calls (e.g. ID = 23, SystemProcessorStatistics, and ID = 24, + SystemDpcInformation) incorrectly return a length of zero, so we + manually adjust the length to the correct value. */ + if ( !ulSize ) + { + if (dwType == 23) + ulSize = 6 * sizeof (ULONG); + else if (dwType == 24) + ulSize = 5 * sizeof (ULONG); + } + + /* If we got some data back, add it to the entropy pool. */ + if (ulSize > 0 && ulSize <= PERFORMANCE_BUFFER_SIZE - 2048) + { + if (debug_me) + log_debug ("rndw32#slow_gatherer: %lu bytes from sysinfo %ld\n", + ulSize, dwType); + (*add) (buffer, ulSize, requester); + no_results++; + } + } + + /* Now we would do the same for the process information. This + call would rather ugly in that it requires an exact length + match for the data returned, failing with a + STATUS_INFO_LENGTH_MISMATCH error code (0xC0000004) if the + length isn't an exact match. It requires a compiler to handle + complex nested structs, alignment issues, and so on, and + without the headers in which the entries are declared it's + almost impossible to do. Thus we don't. */ + + + /* Finally, do the same for the system power status information. There + are only a limited number of useful information types available so we + restrict ourselves to the useful types. In addition since this + function doesn't return length information, we have to hardcode in + length data. */ + if (pNtPowerInformation) + { + static const struct { int type; int size; } powerInfo[] = { + { 0, 128 }, /* SystemPowerPolicyAc */ + { 1, 128 }, /* SystemPowerPolicyDc */ + { 4, 64 }, /* SystemPowerCapabilities */ + { 5, 48 }, /* SystemBatteryState */ + { 11, 48 }, /* ProcessorInformation */ + { 12, 24 }, /* SystemPowerInformation */ + { -1, -1 } + }; + int i; + + /* The 100 is a failsafe limit. */ + for (i = 0; powerInfo[i].type != -1 && i < 100; i++ ) + { + /* Query the info for this ID */ + dwResult = pNtPowerInformation (powerInfo[i].type, NULL, 0, buffer, + PERFORMANCE_BUFFER_SIZE - 2048); + if (dwResult != ERROR_SUCCESS) + continue; + if (debug_me) + log_debug ("rndw32#slow_gatherer: %u bytes from powerinfo %d\n", + powerInfo[i].size, i); + (*add) (buffer, powerInfo[i].size, requester); + no_results++; + } + gcry_assert (i < 100); + } + xfree (buffer); + + /* We couldn't get enough results from the kernel, fall back to the + somewhat troublesome registry poll. */ + if (no_results < 15) + registry_poll (add, requester); +} + + +int +_gcry_rndw32_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + static int is_initialized; + size_t n; + + if (!level) + return 0; + + /* We don't differentiate between level 1 and 2 here because there + is no internal entropy pool as a scary resource. It may all work + slower, but because our entropy source will never block but + deliver some not easy to measure entropy, we assume level 2. */ + + if (!is_initialized) + { + OSVERSIONINFO osvi = { sizeof( osvi ) }; + const char *s; + + if ((s = getenv ("GCRYPT_RNDW32_DBG")) && atoi (s) > 0) + debug_me = 1; + + GetVersionEx( &osvi ); + if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) + log_fatal ("can only run on a Windows NT platform\n" ); + system_is_w2000 = (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0); + + init_system_rng (); + is_initialized = 1; + } + + if (debug_me) + log_debug ("rndw32#gather_random: ori=%d len=%u lvl=%d\n", + origin, (unsigned int)length, level ); + + slow_gatherer (add, origin); + + /* Round requested LENGTH up to full 32 bytes. */ + n = _gcry_rndjent_poll (add, origin, ((length + 31) / 32) * 32); + + if (debug_me) + log_debug ("rndw32#gather_random: jent contributed extra %u bytes\n", + (unsigned int)n); + + return 0; +} + + + +void +_gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin) +{ + static int addedFixedItems = 0; + + if ( debug_me ) + log_debug ("rndw32#gather_random_fast: ori=%d\n", origin ); + + /* Get various basic pieces of system information: Handle of active + window, handle of window with mouse capture, handle of clipboard + owner handle of start of clpboard viewer list, pseudohandle of + current process, current process ID, pseudohandle of current + thread, current thread ID, handle of desktop window, handle of + window with keyboard focus, whether system queue has any events, + cursor position for last message, 1 ms time for last message, + handle of window with clipboard open, handle of process heap, + handle of procs window station, types of events in input queue, + and milliseconds since Windows was started. On 64-bit platform + some of these return values are pointers and thus 64-bit wide. + We discard the upper 32-bit of those values. */ + + { + byte buffer[20*sizeof(unsigned long)], *bufptr; + + bufptr = buffer; +#define ADDINT(f) do { unsigned long along = (unsigned long)(f); \ + memcpy (bufptr, &along, sizeof (along) ); \ + bufptr += sizeof (along); \ + } while (0) +#define ADDPTR(f) do { void *aptr = (f); \ + ADDINT((SIZE_T)aptr); \ + } while (0) + + ADDPTR ( GetActiveWindow ()); + ADDPTR ( GetCapture ()); + ADDPTR ( GetClipboardOwner ()); + ADDPTR ( GetClipboardViewer ()); + ADDPTR ( GetCurrentProcess ()); + ADDINT ( GetCurrentProcessId ()); + ADDPTR ( GetCurrentThread ()); + ADDINT ( GetCurrentThreadId ()); + ADDPTR ( GetDesktopWindow ()); + ADDPTR ( GetFocus ()); + ADDINT ( GetInputState ()); + ADDINT ( GetMessagePos ()); + ADDINT ( GetMessageTime ()); + ADDPTR ( GetOpenClipboardWindow ()); + ADDPTR ( GetProcessHeap ()); + ADDPTR ( GetProcessWindowStation ()); + /* Following function in some cases stops returning events, and cannot + be used as an entropy source. */ + /*ADDINT ( GetQueueStatus (QS_ALLEVENTS));*/ + ADDINT ( GetTickCount ()); + + gcry_assert ( bufptr-buffer < sizeof (buffer) ); + (*add) ( buffer, bufptr-buffer, origin ); +#undef ADDINT +#undef ADDPTR + } + + /* Get multiword system information: Current caret position, current + mouse cursor position. */ + { + POINT point; + + GetCaretPos (&point); + (*add) ( &point, sizeof (point), origin ); + GetCursorPos (&point); + (*add) ( &point, sizeof (point), origin ); + } + + /* Get percent of memory in use, bytes of physical memory, bytes of + free physical memory, bytes in paging file, free bytes in paging + file, user bytes of address space, and free user bytes. */ + { + MEMORYSTATUS memoryStatus; + + memoryStatus.dwLength = sizeof (MEMORYSTATUS); + GlobalMemoryStatus (&memoryStatus); + (*add) ( &memoryStatus, sizeof (memoryStatus), origin ); + } + + /* Get thread and process creation time, exit time, time in kernel + mode, and time in user mode in 100ns intervals. */ + { + HANDLE handle; + FILETIME creationTime, exitTime, kernelTime, userTime; + SIZE_T minimumWorkingSetSize, maximumWorkingSetSize; + + handle = GetCurrentThread (); + GetThreadTimes (handle, &creationTime, &exitTime, + &kernelTime, &userTime); + (*add) ( &creationTime, sizeof (creationTime), origin ); + (*add) ( &exitTime, sizeof (exitTime), origin ); + (*add) ( &kernelTime, sizeof (kernelTime), origin ); + (*add) ( &userTime, sizeof (userTime), origin ); + + handle = GetCurrentProcess (); + GetProcessTimes (handle, &creationTime, &exitTime, + &kernelTime, &userTime); + (*add) ( &creationTime, sizeof (creationTime), origin ); + (*add) ( &exitTime, sizeof (exitTime), origin ); + (*add) ( &kernelTime, sizeof (kernelTime), origin ); + (*add) ( &userTime, sizeof (userTime), origin ); + + /* Get the minimum and maximum working set size for the current + process. */ + GetProcessWorkingSetSize (handle, &minimumWorkingSetSize, + &maximumWorkingSetSize); + /* On 64-bit system, discard the high 32-bits. */ + (*add) ( &minimumWorkingSetSize, sizeof (int), origin ); + (*add) ( &maximumWorkingSetSize, sizeof (int), origin ); + } + + + /* The following are fixed for the lifetime of the process so we only + * add them once */ + if (!addedFixedItems) + { + STARTUPINFO startupInfo; + + /* Get name of desktop, console window title, new window + position and size, window flags, and handles for stdin, + stdout, and stderr. */ + startupInfo.cb = sizeof (STARTUPINFO); + GetStartupInfo (&startupInfo); + (*add) ( &startupInfo, sizeof (STARTUPINFO), origin ); + addedFixedItems = 1; + } + + /* The performance of QPC varies depending on the architecture it's + running on and on the OS, the MS documentation is vague about the + details because it varies so much. Under Win9x/ME it reads the + 1.193180 MHz PIC timer. Under NT/Win2K/XP it may or may not read the + 64-bit TSC depending on the HAL and assorted other circumstances, + generally on machines with a uniprocessor HAL + KeQueryPerformanceCounter() uses a 3.579545MHz timer and on machines + with a multiprocessor or APIC HAL it uses the TSC (the exact time + source is controlled by the HalpUse8254 flag in the kernel). That + choice of time sources is somewhat peculiar because on a + multiprocessor machine it's theoretically possible to get completely + different TSC readings depending on which CPU you're currently + running on, while for uniprocessor machines it's not a problem. + However, the kernel appears to synchronise the TSCs across CPUs at + boot time (it resets the TSC as part of its system init), so this + shouldn't really be a problem. Under WinCE it's completely platform- + dependent, if there's no hardware performance counter available, it + uses the 1ms system timer. + + Another feature of the TSC (although it doesn't really affect us here) + is that mobile CPUs will turn off the TSC when they idle, Pentiums + will change the rate of the counter when they clock-throttle (to + match the current CPU speed), and hyperthreading Pentiums will turn + it off when both threads are idle (this more or less makes sense, + since the CPU will be in the halted state and not executing any + instructions to count). + + To make things unambiguous, we detect a CPU new enough to call RDTSC + directly by checking for CPUID capabilities, and fall back to QPC if + this isn't present. + + On AMD64, TSC is always available and intrinsic is provided for accessing + it. */ +#ifdef __x86_64__ + { + unsigned __int64 aint64; + + /* Note: cryptlib does not discard upper 32 bits of TSC on WIN64, but does + * on WIN32. Is this correct? */ + aint64 = __rdtsc(); + (*add) (&aint64, sizeof(aint64), origin); + } +#else +#ifdef __GNUC__ +/* FIXME: We would need to implement the CPU feature tests first. */ +/* if (cpu_has_feature_rdtsc) */ +/* { */ +/* uint32_t lo, hi; */ + /* We cannot use "=A", since this would use %rax on x86_64. */ +/* __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); */ + /* Ignore high 32 bits, hwich are >1s res. */ +/* (*add) (&lo, 4, origin ); */ +/* } */ +/* else */ +#endif /*!__GNUC__*/ + { + LARGE_INTEGER performanceCount; + + if (QueryPerformanceCounter (&performanceCount)) + { + if ( debug_me ) + log_debug ("rndw32#gather_random_fast: perf data\n"); + (*add) (&performanceCount, sizeof (performanceCount), origin); + } + else + { + /* Millisecond accuracy at best... */ + DWORD aword = GetTickCount (); + (*add) (&aword, sizeof (aword), origin ); + } + } +#endif /*__x86_64__*/ + + +} diff --git a/comm/third_party/libgcrypt/random/rndw32ce.c b/comm/third_party/libgcrypt/random/rndw32ce.c new file mode 100644 index 0000000000..873e84606a --- /dev/null +++ b/comm/third_party/libgcrypt/random/rndw32ce.c @@ -0,0 +1,199 @@ +/* rndw32ce.c - W32CE entropy gatherer + * Copyright (C) 2010 Free Software Foundation, Inc. + * + * Libgcrypt 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. + * + * Libgcrypt 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 program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <stdint.h> + +#include <windows.h> +#include <wincrypt.h> + +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + + +/* The Microsoft docs say that it is suggested to see the buffer with + some extra random. We do this, despite that it is a questionable + suggestion as the OS as better means of collecting entropy than an + application. */ +static size_t filler_used; +static size_t filler_length; +static unsigned char *filler_buffer; + +static void +filler (const void *data, size_t datalen, enum random_origins dummy) +{ + (void)dummy; + if (filler_used + datalen > filler_length) + datalen = filler_length - filler_used; + memcpy (filler_buffer + filler_used, data, datalen); + filler_used += datalen; +} + + +static void +fillup_buffer (unsigned char *buffer, size_t length) +{ + filler_used = 0; + filler_length = length; + filler_buffer = buffer; + + while (filler_used < length) + _gcry_rndw32ce_gather_random_fast (filler, 0); +} + + +int +_gcry_rndw32ce_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + HCRYPTPROV prov; + unsigned char buffer [256]; + DWORD buflen; + + if (!level) + return 0; + + /* Note that LENGTH is not really important because the caller + checks the returned lengths and calls this function until it + feels that enough entropy has been gathered. */ + + buflen = sizeof buffer; + if (length+8 < buflen) + buflen = length+8; /* Return a bit more than requested. */ + + if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL, + (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) ) + log_debug ("CryptAcquireContext failed: rc=%d\n", (int)GetLastError ()); + else + { + fillup_buffer (buffer, buflen); + if (!CryptGenRandom (prov, buflen, buffer)) + log_debug ("CryptGenRandom(%d) failed: rc=%d\n", + (int)buflen, (int)GetLastError ()); + else + (*add) (buffer, buflen, origin); + CryptReleaseContext (prov, 0); + wipememory (buffer, sizeof buffer); + } + + return 0; +} + + + +void +_gcry_rndw32ce_gather_random_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin) +{ + + /* Add word sized values. */ + { +# define ADD(t,f) do { \ + t along = (f); \ + memcpy (bufptr, &along, sizeof (along)); \ + bufptr += sizeof (along); \ + } while (0) + unsigned char buffer[20*sizeof(unsigned long)], *bufptr; + + bufptr = buffer; + ADD (HWND, GetActiveWindow ()); + ADD (HWND, GetCapture ()); + ADD (HWND, GetClipboardOwner ()); + ADD (HANDLE, GetCurrentProcess ()); + ADD (DWORD, GetCurrentProcessId ()); + ADD (HANDLE, GetCurrentThread ()); + ADD (DWORD, GetCurrentThreadId ()); + ADD (HWND, GetDesktopWindow ()); + ADD (HWND, GetFocus ()); + ADD (DWORD, GetMessagePos ()); + ADD (HWND, GetOpenClipboardWindow ()); + ADD (HWND, GetProcessHeap ()); + ADD (DWORD, GetQueueStatus (QS_ALLEVENTS)); + ADD (DWORD, GetTickCount ()); + + gcry_assert ( bufptr-buffer < sizeof (buffer) ); + (*add) ( buffer, bufptr-buffer, origin ); +# undef ADD + } + + /* Get multiword system information: Current caret position, current + mouse cursor position. */ + { + POINT point; + + GetCaretPos (&point); + (*add) ( &point, sizeof (point), origin ); + GetCursorPos (&point); + (*add) ( &point, sizeof (point), origin ); + } + + /* Get percent of memory in use, bytes of physical memory, bytes of + free physical memory, bytes in paging file, free bytes in paging + file, user bytes of address space, and free user bytes. */ + { + MEMORYSTATUS memoryStatus; + + memoryStatus.dwLength = sizeof (MEMORYSTATUS); + GlobalMemoryStatus (&memoryStatus); + (*add) ( &memoryStatus, sizeof (memoryStatus), origin ); + } + + + /* Get thread and process creation time, exit time, time in kernel + mode, and time in user mode in 100ns intervals. */ + { + HANDLE handle; + FILETIME creationTime, exitTime, kernelTime, userTime; + + handle = GetCurrentThread (); + GetThreadTimes (handle, &creationTime, &exitTime, + &kernelTime, &userTime); + (*add) ( &creationTime, sizeof (creationTime), origin ); + (*add) ( &exitTime, sizeof (exitTime), origin ); + (*add) ( &kernelTime, sizeof (kernelTime), origin ); + (*add) ( &userTime, sizeof (userTime), origin ); + + handle = GetCurrentThread (); + GetThreadTimes (handle, &creationTime, &exitTime, + &kernelTime, &userTime); + (*add) ( &creationTime, sizeof (creationTime), origin ); + (*add) ( &exitTime, sizeof (exitTime), origin ); + (*add) ( &kernelTime, sizeof (kernelTime), origin ); + (*add) ( &userTime, sizeof (userTime), origin ); + + } + + + /* In case the OEM provides a high precision timer get this. If + none is available the default implementation returns the + GetTickCount. */ + { + LARGE_INTEGER performanceCount; + + if (QueryPerformanceCounter (&performanceCount)) + (*add) (&performanceCount, sizeof (performanceCount), origin); + } + +} |