From 8175e3ddda29a03d5e0aec4a1774339414996565 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 31 May 2020 18:23:04 +0200 Subject: [PATCH] getrandom: Add support for native Windows. * lib/getrandom.c: Include , , , . (CRYPT_VERIFY_CONTEXT): New macro. (LoadLibrary, CryptAcquireContext): Redirect to the variant with suffix 'A'. (GetProcAddress): New macro. (BCryptGenRandomFuncType): New type. (BCryptGenRandomFunc, initialized): New variables. (initialize): New function. (getrandom): On native Windows, use API when available, and API as fallback. * m4/getrandom.m4 (gl_FUNC_GETRANDOM): Set LIB_GETRANDOM. * modules/getrandom (Link): New section. * modules/getentropy (Link): Likewise. * modules/getrandom-tests (Makefile.am): Link test-getrandom against $(LIB_GETRANDOM). * modules/getentropy-tests (Makefile.am): Link test-getentropy against $(LIB_GETRANDOM). * modules/sys_random-c++-tests (Makefile.am): Link test-sys_random-c++ against $(LIB_GETRANDOM). * doc/glibc-functions/getrandom.texi: Mention the native Windows support. --- ChangeLog | 26 ++++++++ doc/glibc-functions/getrandom.texi | 4 +- lib/getrandom.c | 104 ++++++++++++++++++++++++++++- m4/getrandom.m4 | 30 ++++++++- modules/getentropy | 3 + modules/getentropy-tests | 1 + modules/getrandom | 3 + modules/getrandom-tests | 1 + modules/sys_random-c++-tests | 1 + 9 files changed, 168 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index f7c9b4dfb0..072d2d49af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2020-05-31 Bruno Haible + + getrandom: Add support for native Windows. + * lib/getrandom.c: Include , , , + . + (CRYPT_VERIFY_CONTEXT): New macro. + (LoadLibrary, CryptAcquireContext): Redirect to the variant with suffix + 'A'. + (GetProcAddress): New macro. + (BCryptGenRandomFuncType): New type. + (BCryptGenRandomFunc, initialized): New variables. + (initialize): New function. + (getrandom): On native Windows, use API when available, and + API as fallback. + * m4/getrandom.m4 (gl_FUNC_GETRANDOM): Set LIB_GETRANDOM. + * modules/getrandom (Link): New section. + * modules/getentropy (Link): Likewise. + * modules/getrandom-tests (Makefile.am): Link test-getrandom against + $(LIB_GETRANDOM). + * modules/getentropy-tests (Makefile.am): Link test-getentropy against + $(LIB_GETRANDOM). + * modules/sys_random-c++-tests (Makefile.am): Link test-sys_random-c++ + against $(LIB_GETRANDOM). + * doc/glibc-functions/getrandom.texi: Mention the native Windows + support. + 2020-05-31 Bruno Haible getrandom: Simplify the determination of the random number devices. diff --git a/doc/glibc-functions/getrandom.texi b/doc/glibc-functions/getrandom.texi index 2d93556537..99712c77b7 100644 --- a/doc/glibc-functions/getrandom.texi +++ b/doc/glibc-functions/getrandom.texi @@ -22,7 +22,7 @@ Portability problems fixed by Gnulib: @item This function is missing on some platforms: glibc 2.24, Mac OS X 10.5, FreeBSD 11.0, NetBSD 5.0, OpenBSD 3.8, -Solaris 11.0, Android 9.0. +Solaris 11.0, mingw, MSVC 14, Android 9.0. @item This function has a different return type on some platforms: Solaris 11.4. @@ -32,5 +32,5 @@ Portability problems not fixed by Gnulib: @itemize @item This function is missing on some platforms: -Minix 3.1.8, IRIX 6.5, mingw, MSVC 14. +Minix 3.1.8, IRIX 6.5. @end itemize diff --git a/lib/getrandom.c b/lib/getrandom.c index 0cc3dc3d85..ad49cae896 100644 --- a/lib/getrandom.c +++ b/lib/getrandom.c @@ -21,14 +21,65 @@ #include +#include #include #include #include +#if defined _WIN32 && ! defined __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include +# include +# if !HAVE_LIB_BCRYPT +# include +# ifndef CRYPT_VERIFY_CONTEXT +# define CRYPT_VERIFY_CONTEXT 0xF0000000 +# endif +# endif +#endif + #include "minmax.h" +#if defined _WIN32 && ! defined __CYGWIN__ + +/* Don't assume that UNICODE is not defined. */ +# undef LoadLibrary +# define LoadLibrary LoadLibraryA +# undef CryptAcquireContext +# define CryptAcquireContext CryptAcquireContextA + +# if !HAVE_LIB_BCRYPT + +/* Avoid warnings from gcc -Wcast-function-type. */ +# define GetProcAddress \ + (void *) GetProcAddress + +/* BCryptGenRandom with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag works only + starting with Windows 7. */ +typedef NTSTATUS (WINAPI * BCryptGenRandomFuncType) (BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG); +static BCryptGenRandomFuncType BCryptGenRandomFunc = NULL; +static BOOL initialized = FALSE; + +static void +initialize (void) +{ + HMODULE bcrypt = LoadLibrary ("bcrypt.dll"); + if (bcrypt != NULL) + { + BCryptGenRandomFunc = + (BCryptGenRandomFuncType) GetProcAddress (bcrypt, "BCryptGenRandom"); + } + initialized = TRUE; +} + +# else + +# define BCryptGenRandomFunc BCryptGenRandom + +# endif + +#else /* These devices exist on all platforms except native Windows. */ -#if !(defined _WIN32 && ! defined __CYGWIN__) /* Name of a device through which the kernel returns high quality random numbers, from an entropy pool. When the pool is empty, the call blocks @@ -52,7 +103,56 @@ ssize_t getrandom (void *buffer, size_t length, unsigned int flags) #undef getrandom { -#if HAVE_GETRANDOM +#if defined _WIN32 && ! defined __CYGWIN__ + /* BCryptGenRandom, defined in + + with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag + works in Windows 7 and newer. */ + static int bcrypt_not_working /* = 0 */; + if (!bcrypt_not_working) + { +# if !HAVE_LIB_BCRYPT + if (!initialized) + initialize (); +# endif + if (BCryptGenRandomFunc != NULL + && BCryptGenRandomFunc (NULL, buffer, length, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) + == 0 /*STATUS_SUCCESS*/) + return length; + bcrypt_not_working = 1; + } +# if !HAVE_LIB_BCRYPT + /* CryptGenRandom, defined in + + works in older releases as well, but is now deprecated. + CryptAcquireContext, defined in + */ + { + static int crypt_initialized /* = 0 */; + static HCRYPTPROV provider; + if (!crypt_initialized) + { + if (CryptAcquireContext (&provider, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFY_CONTEXT)) + crypt_initialized = 1; + else + crypt_initialized = -1; + } + if (crypt_initialized >= 0) + { + if (!CryptGenRandom (provider, length, buffer)) + { + errno = EIO; + return -1; + } + return length; + } + } +# endif + errno = ENOSYS; + return -1; +#elif HAVE_GETRANDOM return getrandom (buffer, length, flags); #else static int randfd[2] = { -1, -1 }; diff --git a/m4/getrandom.m4 b/m4/getrandom.m4 index 779c6ad832..37fb10023a 100644 --- a/m4/getrandom.m4 +++ b/m4/getrandom.m4 @@ -1,4 +1,4 @@ -# getrandom.m4 serial 4 +# getrandom.m4 serial 5 dnl Copyright 2020 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -33,4 +33,32 @@ AC_DEFUN([gl_FUNC_GETRANDOM], REPLACE_GETRANDOM=1 fi fi + + case "$host_os" in + mingw*) + AC_CACHE_CHECK([whether the bcrypt library is guaranteed to be present], + [gl_cv_lib_assume_bcrypt], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[#if !(_WIN32_WINNT >= _WIN32_WINNT_WIN7) + cannot assume it + #endif + ]]) + ], + [gl_cv_lib_assume_bcrypt=yes], + [gl_cv_lib_assume_bcrypt=no]) + ]) + if test $gl_cv_lib_assume_bcrypt = yes; then + AC_DEFINE([HAVE_LIB_BCRYPT], [1], + [Define to 1 if the bcrypt library is guaranteed to be present.]) + LIB_GETRANDOM='-lbcrypt' + else + LIB_GETRANDOM='-ladvapi32' + fi + ;; + *) + LIB_GETRANDOM= ;; + esac + AC_SUBST([LIB_GETRANDOM]) ]) diff --git a/modules/getentropy b/modules/getentropy index 9696c1e1d5..680aa4716b 100644 --- a/modules/getentropy +++ b/modules/getentropy @@ -22,6 +22,9 @@ Makefile.am: Include: +Link: +$(LIB_GETRANDOM) + License: LGPL diff --git a/modules/getentropy-tests b/modules/getentropy-tests index b5c4b1144e..7ad786109c 100644 --- a/modules/getentropy-tests +++ b/modules/getentropy-tests @@ -10,3 +10,4 @@ configure.ac: Makefile.am: TESTS += test-getentropy check_PROGRAMS += test-getentropy +test_getentropy_LDADD = $(LDADD) $(LIB_GETRANDOM) diff --git a/modules/getrandom b/modules/getrandom index 8aa4be2b78..76437eb5ad 100644 --- a/modules/getrandom +++ b/modules/getrandom @@ -23,6 +23,9 @@ Makefile.am: Include: +Link: +$(LIB_GETRANDOM) + License: LGPL diff --git a/modules/getrandom-tests b/modules/getrandom-tests index 8982173613..b7f64dd205 100644 --- a/modules/getrandom-tests +++ b/modules/getrandom-tests @@ -10,3 +10,4 @@ configure.ac: Makefile.am: TESTS += test-getrandom check_PROGRAMS += test-getrandom +test_getrandom_LDADD = $(LDADD) @LIB_GETRANDOM@ diff --git a/modules/sys_random-c++-tests b/modules/sys_random-c++-tests index e07d81f0e7..5b3c505fd4 100644 --- a/modules/sys_random-c++-tests +++ b/modules/sys_random-c++-tests @@ -15,4 +15,5 @@ if ANSICXX TESTS += test-sys_random-c++ check_PROGRAMS += test-sys_random-c++ test_sys_random_c___SOURCES = test-sys_random-c++.cc +test_sys_random_c___LDADD = $(LDADD) $(LIB_GETRANDOM) endif -- 2.39.5