From: Viktor Szakats Date: Mon, 4 Jul 2022 09:38:24 +0000 (+0000) Subject: windows: improve random source X-Git-Tag: curl-7_85_0~204 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=76172511e7adcf720f4c77bd91f49278300ec97e;p=thirdparty%2Fcurl.git windows: improve random source - 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 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f93bedf6c..b2204fe588 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/configure.ac b/configure.ac index de2dee5a48..9439fa049f 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/docs/examples/Makefile.m32 b/docs/examples/Makefile.m32 index 15eaf82b3a..4948253ab7 100644 --- a/docs/examples/Makefile.m32 +++ b/docs/examples/Makefile.m32 @@ -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 diff --git a/lib/Makefile.m32 b/lib/Makefile.m32 index bf8d1b400a..ec04cb0cec 100644 --- a/lib/Makefile.m32 +++ b/lib/Makefile.m32 @@ -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 diff --git a/lib/rand.c b/lib/rand.c index dd02f52680..c6fd47e7f6 100644 --- a/lib/rand.c +++ b/lib/rand.c @@ -38,6 +38,64 @@ #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 +# 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 +# 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 */ diff --git a/lib/rand.h b/lib/rand.h index 2f442f5816..99f25b94e1 100644 --- a/lib/rand.h +++ b/lib/rand.h @@ -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 */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 7e42285828..cfeec002cb 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -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, diff --git a/src/Makefile.m32 b/src/Makefile.m32 index b3d3cf9631..c24e15a66d 100644 --- a/src/Makefile.m32 +++ b/src/Makefile.m32 @@ -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