diff options
author | Bruno Haible <bruno@clisp.org> | 2020-05-31 18:23:04 +0200 |
---|---|---|
committer | Bruno Haible <bruno@clisp.org> | 2020-05-31 18:23:04 +0200 |
commit | 8175e3ddda29a03d5e0aec4a1774339414996565 (patch) | |
tree | 6dda6c4f9711a1f925e9929277a42b41c62ce8fd /lib/getrandom.c | |
parent | 053dd57da26bcda9f03180758fce81fffe7747c8 (diff) | |
download | gnulib-8175e3ddda29a03d5e0aec4a1774339414996565.tar.gz |
getrandom: Add support for native Windows.
* lib/getrandom.c: Include <errno.h>, <windows.h>, <bcrypt.h>,
<wincrypt.h>.
(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 <bcrypt.h> API when available, and
<wincrypt.h> 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.
Diffstat (limited to 'lib/getrandom.c')
-rw-r--r-- | lib/getrandom.c | 104 |
1 files changed, 102 insertions, 2 deletions
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 <sys/random.h> +#include <errno.h> #include <fcntl.h> #include <stdbool.h> #include <unistd.h> +#if defined _WIN32 && ! defined __CYGWIN__ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# include <bcrypt.h> +# if !HAVE_LIB_BCRYPT +# include <wincrypt.h> +# 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 <bcrypt.h> + <https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom> + 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 <wincrypt.h> + <https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom> + works in older releases as well, but is now deprecated. + CryptAcquireContext, defined in <wincrypt.h> + <https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta> */ + { + 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 }; |