]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
windows: improve random source
authorViktor Szakats <commit@vsz.me>
Mon, 4 Jul 2022 09:38:24 +0000 (09:38 +0000)
committerViktor Szakats <commit@vsz.me>
Mon, 4 Jul 2022 09:38:24 +0000 (09:38 +0000)
- Use the Windows API to seed the fallback random generator.

  This ensures to always have a random seed, even when libcurl is built
  with a vtls backend lacking a random generator API, such as rustls
  (experimental), GSKit and certain mbedTLS builds, or, when libcurl is
  built without a TLS backend. We reuse the Windows-specific random
  function from the Schannel backend.

- Implement support for `BCryptGenRandom()` [1] on Windows, as a
  replacement for the deprecated `CryptGenRandom()` [2] function.

  It is used as the secure random generator for Schannel, and also to
  provide entropy for libcurl's fallback random generator. The new
  function is supported on Vista and newer via its `bcrypt.dll`. It is
  used automatically when building for supported versions. It also works
  in UWP apps (the old function did not).

- Clear entropy buffer before calling the Windows random generator.

  This avoids using arbitrary application memory as entropy (with
  `CryptGenRandom()`) and makes sure to return in a predictable state
  when an API call fails.

[1] https://docs.microsoft.com/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
[2] https://docs.microsoft.com/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom

Closes #9027

CMakeLists.txt
configure.ac
docs/examples/Makefile.m32
lib/Makefile.m32
lib/rand.c
lib/rand.h
lib/vtls/schannel.c
src/Makefile.m32

index 5f93bedf6c95a90ed708cfb9a2b105419d1d7817..b2204fe588d40179fb5d430d5d094c05ae054d4d 100644 (file)
@@ -1327,6 +1327,8 @@ if(WIN32)
   if(USE_WIN32_CRYPTO OR USE_SCHANNEL)
     list(APPEND CURL_LIBS "advapi32" "crypt32")
   endif()
+
+  list(APPEND CURL_LIBS "bcrypt")
 endif()
 
 if(MSVC)
index de2dee5a484ed5f4db52789b143b5a0fda722cc6..9439fa049faddc81e111fc9b55f498579c1c291b 100644 (file)
@@ -500,6 +500,28 @@ case $host in
     ;;
 esac
 
+# Detect original MinGW (not MinGW-w64)
+curl_mingw_original=no
+case $host in
+  *-*-mingw32*)
+    AC_MSG_CHECKING([using original MinGW (not MinGW-w64)])
+    AC_COMPILE_IFELSE([
+      AC_LANG_PROGRAM([[
+#include <_mingw.h>
+      ]],[[
+#if defined(__MINGW64_VERSION_MAJOR)
+#error
+#endif
+      ]])
+    ],[
+      curl_mingw_original=yes
+      AC_MSG_RESULT([yes])
+    ],[
+      AC_MSG_RESULT([no])
+    ])
+    ;;
+esac
+
 dnl **********************************************************************
 dnl Compilation based checks should not be done before this point.
 dnl **********************************************************************
@@ -1917,6 +1939,12 @@ if test "x$USE_WIN32_CRYPTO" = "x1" -o "x$USE_SCHANNEL" = "x1"; then
   LIBS="-ladvapi32 -lcrypt32 $LIBS"
 fi
 
+dnl link bcrypt for BCryptGenRandom() (used when building for Vista or newer)
+if test "x$curl_cv_native_windows" = "xyes" &&
+   test "x$curl_mingw_original" = "xno"; then
+  LIBS="-lbcrypt $LIBS"
+fi
+
 case "x$OPENSSL_ENABLED$GNUTLS_ENABLED$NSS_ENABLED$MBEDTLS_ENABLED$WOLFSSL_ENABLED$SCHANNEL_ENABLED$SECURETRANSPORT_ENABLED$BEARSSL_ENABLED$AMISSL_ENABLED$RUSTLS_ENABLED"
 in
 x)
index 15eaf82b3a8b794be74dd89f9c5083a1bcc2dfaa..4948253ab79149d8ba6a9941f8d1d7bd2915362b 100644 (file)
@@ -266,7 +266,7 @@ ifdef SSH2
   curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2
   ifdef SCHANNEL
     ifndef DYN
-      curl_LDADD += -lbcrypt -lcrypt32
+      curl_LDADD += -lcrypt32
     endif
   endif
 endif
@@ -374,7 +374,7 @@ ifndef USE_LDAP_OPENLDAP
   curl_LDADD += -lwldap32
 endif
 endif
-curl_LDADD += -lws2_32
+curl_LDADD += -lws2_32 -lbcrypt
 
 # Makefile.inc provides the check_PROGRAMS and COMPLICATED_EXAMPLES defines
 include Makefile.inc
index bf8d1b400a1ea85ffa9e3c14277d87ab4348bcdc..ec04cb0cec87a42b065af10666561836d00046f7 100644 (file)
@@ -279,7 +279,7 @@ ifdef SSH2
   DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2
   ifdef SCHANNEL
     ifndef DYN
-      DLL_LIBS += -lbcrypt -lcrypt32
+      DLL_LIBS += -lcrypt32
     endif
   endif
 endif
@@ -400,7 +400,7 @@ ifndef USE_LDAP_OPENLDAP
   DLL_LIBS += -lwldap32
 endif
 endif
-DLL_LIBS += -lws2_32
+DLL_LIBS += -lws2_32 -lbcrypt
 
 # Makefile.inc provides the CSOURCES and HHEADERS defines
 include Makefile.inc
index dd02f5268011daf251cc00aa160ed28e95631aaf..c6fd47e7f69ec136f47d2ef366a845123e51e714 100644 (file)
 #include "curl_memory.h"
 #include "memdebug.h"
 
+#ifdef WIN32
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+#  define HAVE_MINGW_ORIGINAL
+#endif
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \
+  !defined(HAVE_MINGW_ORIGINAL)
+#  define HAVE_WIN_BCRYPTGENRANDOM
+#  include <bcrypt.h>
+#  ifdef _MSC_VER
+#    pragma comment(lib, "bcrypt.lib")
+#  endif
+#  ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG
+#  define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
+#  endif
+#  ifndef STATUS_SUCCESS
+#  define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+#  endif
+#elif defined(USE_WIN32_CRYPTO)
+#  include <wincrypt.h>
+#  ifdef _MSC_VER
+#    pragma comment(lib, "advapi32.lib")
+#  endif
+#endif
+
+CURLcode Curl_win32_random(unsigned char *entropy, size_t length)
+{
+  memset(entropy, 0, length);
+
+#if defined(HAVE_WIN_BCRYPTGENRANDOM)
+  if(BCryptGenRandom(NULL, entropy, (ULONG)length,
+                     BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS)
+    return CURLE_FAILED_INIT;
+
+  return CURLE_OK;
+#elif defined(USE_WIN32_CRYPTO)
+  {
+    HCRYPTPROV hCryptProv = 0;
+
+    if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
+                            CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+      return CURLE_FAILED_INIT;
+
+    if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
+      CryptReleaseContext(hCryptProv, 0UL);
+      return CURLE_FAILED_INIT;
+    }
+
+    CryptReleaseContext(hCryptProv, 0UL);
+  }
+  return CURLE_OK;
+#else
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+#endif
+
 static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
 {
   unsigned int r;
@@ -73,6 +131,14 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
 
   /* ---- non-cryptographic version following ---- */
 
+#ifdef WIN32
+  if(!seeded) {
+    result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd));
+    if(result != CURLE_NOT_BUILT_IN)
+      return result;
+  }
+#endif
+
 #if defined(RANDOM_FILE) && !defined(WIN32)
   if(!seeded) {
     /* if there's a random file to read a seed from, use it */
index 2f442f5816e18a9fed0ea262067174b372562d9b..99f25b94e1e69d296d0a727b59b8ae2e149450ea 100644 (file)
@@ -48,4 +48,10 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num);
 CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
                        size_t num);
 
+#ifdef WIN32
+/* Random generator shared between the Schannel vtls and Curl_rand*()
+   functions */
+CURLcode Curl_win32_random(unsigned char *entropy, size_t length);
+#endif
+
 #endif /* HEADER_CURL_RAND_H */
index 7e422858288722df34d08dd39928b290c55ef965..cfeec002cb85c17153eb3155655b980b6c7e42ce 100644 (file)
@@ -53,6 +53,7 @@
 #include "curl_printf.h"
 #include "multiif.h"
 #include "version_win32.h"
+#include "rand.h"
 
 /* The last #include file should be: */
 #include "curl_memory.h"
@@ -2298,21 +2299,9 @@ static size_t schannel_version(char *buffer, size_t size)
 static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
                                 unsigned char *entropy, size_t length)
 {
-  HCRYPTPROV hCryptProv = 0;
-
   (void)data;
 
-  if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
-                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
-    return CURLE_FAILED_INIT;
-
-  if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
-    CryptReleaseContext(hCryptProv, 0UL);
-    return CURLE_FAILED_INIT;
-  }
-
-  CryptReleaseContext(hCryptProv, 0UL);
-  return CURLE_OK;
+  return Curl_win32_random(entropy, length);
 }
 
 static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
index b3d3cf9631f082fa6d380ef54030debdaf15dd03..c24e15a66dcff66addfc0bc037bd69aea50c37bb 100644 (file)
@@ -291,7 +291,7 @@ ifdef SSH2
   curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2
   ifdef SCHANNEL
     ifndef DYN
-      curl_LDADD += -lbcrypt -lcrypt32
+      curl_LDADD += -lcrypt32
     endif
   endif
 endif
@@ -399,7 +399,7 @@ ifndef USE_LDAP_OPENLDAP
 curl_LDADD += -lwldap32
 endif
 endif
-curl_LDADD += -lws2_32
+curl_LDADD += -lws2_32 -lbcrypt
 
 # Makefile.inc provides the CSOURCES and HHEADERS defines
 include Makefile.inc