From: Bruno Haible <bruno@clisp.org>
To: bug-gnulib@gnu.org
Cc: Jeffrey Walton <noloader@gmail.com>, Paul Eggert <eggert@cs.ucla.edu>
Subject: getrandom: Add support for native Windows
Date: Sun, 31 May 2020 18:26:52 +0200 [thread overview]
Message-ID: <2353550.NELAItI0gM@omega> (raw)
In-Reply-To: <20200525193753.12395-1-eggert@cs.ucla.edu>
Native Windows is the only platform without the /dev/random and
/dev/urandom devices; it therefore needs special code.
Jeffrey Walton wrote:
> On modern Windows systems you should use BCryptGenRandom for the
> material. CryptGenRandom is deprecated.
Thanks for the pointer.
This patch implements it: try BCryptGenRandom first, and fall back on
CryptGenRandom.
2020-05-31 Bruno Haible <bruno@clisp.org>
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.
diff --git a/doc/glibc-functions/getrandom.texi b/doc/glibc-functions/getrandom.texi
index 2d93556..99712c7 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 0cc3dc3..ad49cae 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 };
diff --git a/m4/getrandom.m4 b/m4/getrandom.m4
index 779c6ad..37fb100 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 <windows.h>]],
+ [[#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 9696c1e..680aa47 100644
--- a/modules/getentropy
+++ b/modules/getentropy
@@ -22,6 +22,9 @@ Makefile.am:
Include:
<unistd.h>
+Link:
+$(LIB_GETRANDOM)
+
License:
LGPL
diff --git a/modules/getentropy-tests b/modules/getentropy-tests
index b5c4b11..7ad7861 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 8aa4be2..76437eb 100644
--- a/modules/getrandom
+++ b/modules/getrandom
@@ -23,6 +23,9 @@ Makefile.am:
Include:
<sys/random.h>
+Link:
+$(LIB_GETRANDOM)
+
License:
LGPL
diff --git a/modules/getrandom-tests b/modules/getrandom-tests
index 8982173..b7f64dd 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 e07d81f..5b3c505 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
next prev parent reply other threads:[~2020-05-31 16:27 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-25 19:37 [PATCH] getentropy, getrandom: new modules Paul Eggert
2020-05-30 12:58 ` Bruno Haible
2020-05-30 22:43 ` Paul Eggert
2020-05-31 11:23 ` getrandom vs. crypto/gc-random Bruno Haible
2020-05-31 11:47 ` Bruno Haible
2020-05-31 13:14 ` Jeffrey Walton
2020-05-31 13:23 ` Simon Josefsson
2020-05-31 19:02 ` Bruno Haible
2020-06-01 13:45 ` Jeffrey Walton
2020-06-01 16:53 ` Bruno Haible
2020-06-01 18:13 ` Paul Eggert
2020-06-01 19:01 ` Bruno Haible
2020-06-01 23:00 ` Paul Eggert
2020-06-01 23:51 ` Bruno Haible
2020-06-02 0:04 ` Paul Eggert
2020-05-30 13:17 ` [PATCH] getentropy, getrandom: new modules Bruno Haible
2020-05-30 14:23 ` Bruno Haible
2020-05-30 23:06 ` sys_random: Work around macOS bug Bruno Haible
2020-05-30 23:28 ` Jeffrey Walton
2020-05-31 10:29 ` Apple platforms Bruno Haible
2020-05-30 15:34 ` [PATCH] getentropy, getrandom: new modules Bruno Haible
2020-05-30 23:14 ` fix list of crypto devices for NetBSD, OpenBSD Bruno Haible
2020-05-31 10:57 ` fix list of crypto devices for Solaris Bruno Haible
2020-05-31 16:26 ` Bruno Haible [this message]
2020-05-31 16:41 ` getrandom: Add support for native Windows Jeffrey Walton
2020-05-31 16:49 ` getrandom: doc and test tweaks Bruno Haible
2020-05-31 18:15 ` [PATCH] getentropy, getrandom: new modules Bruno Haible
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2353550.NELAItI0gM@omega \
--to=bruno@clisp.org \
--cc=bug-gnulib@gnu.org \
--cc=eggert@cs.ucla.edu \
--cc=noloader@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).