version_win32: Check build number and platform id

Prior to this change the build number was not checked during version
comparison, and the platform id was supposed to be checked but wasn't.

Checking the build number is required for enabling "evergreen"
Windows 10/11 features (like TLS 1.3).

Ref: https://github.com/curl/curl/pull/7784

Closes https://github.com/curl/curl/pull/7824
Closes https://github.com/curl/curl/pull/7867
This commit is contained in:
Wyatt O'Day 2021-10-07 06:58:39 -04:00 committed by Jay Satiro
parent 3467e89bb9
commit 7da636cad5
8 changed files with 77 additions and 27 deletions

View File

@ -1127,7 +1127,7 @@ void Curl_sndbufset(curl_socket_t sockfd)
static int detectOsState = DETECT_OS_NONE;
if(detectOsState == DETECT_OS_NONE) {
if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL))
detectOsState = DETECT_OS_VISTA_OR_LATER;
else

View File

@ -83,7 +83,7 @@ CURLcode Curl_sspi_global_init(void)
* have both these DLLs (security.dll forwards calls to secur32.dll) */
/* Load SSPI dll into the address space of the calling process */
if(curlx_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL))
if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
s_hSecDll = Curl_load_library(TEXT("security.dll"));
else
s_hSecDll = Curl_load_library(TEXT("secur32.dll"));

View File

@ -104,7 +104,7 @@ CURLcode Curl_win32_init(long flags)
/* curlx_verify_windows_version must be called during init at least once
because it has its own initialization routine. */
if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
Curl_isVistaOrGreater = TRUE;
}

View File

@ -57,6 +57,8 @@ struct OUR_OSVERSIONINFOEXW {
*
* majorVersion [in] - The major version number.
* minorVersion [in] - The minor version number.
* buildVersion [in] - The build version number. If 0, this parameter is
* ignored.
* platform [in] - The optional platform identifier.
* condition [in] - The test condition used to specifier whether we are
* checking a version less then, equal to or greater than
@ -67,6 +69,7 @@ struct OUR_OSVERSIONINFOEXW {
*/
bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion,
const unsigned int buildVersion,
const PlatformIdentifier platform,
const VersionCondition condition)
{
@ -118,34 +121,52 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_LESS_THAN:
if(osver.dwMajorVersion < majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion < minorVersion))
osver.dwMinorVersion < minorVersion) ||
(buildVersion != 0 &&
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
osver.dwBuildNumber < buildVersion)))
matched = TRUE;
break;
case VERSION_LESS_THAN_EQUAL:
if(osver.dwMajorVersion < majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion <= minorVersion))
osver.dwMinorVersion < minorVersion) ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
(buildVersion == 0 ||
osver.dwBuildNumber <= buildVersion)))
matched = TRUE;
break;
case VERSION_EQUAL:
if(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion)
osver.dwMinorVersion == minorVersion &&
(buildVersion == 0 ||
osver.dwBuildNumber == buildVersion))
matched = TRUE;
break;
case VERSION_GREATER_THAN_EQUAL:
if(osver.dwMajorVersion > majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion >= minorVersion))
osver.dwMinorVersion > minorVersion) ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
(buildVersion == 0 ||
osver.dwBuildNumber >= buildVersion)))
matched = TRUE;
break;
case VERSION_GREATER_THAN:
if(osver.dwMajorVersion > majorVersion ||
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion > minorVersion))
osver.dwMinorVersion > minorVersion) ||
(buildVersion != 0 &&
(osver.dwMajorVersion == majorVersion &&
osver.dwMinorVersion == minorVersion &&
osver.dwBuildNumber > buildVersion)))
matched = TRUE;
break;
}
@ -161,6 +182,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case PLATFORM_WINNT:
if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
matched = FALSE;
break;
default: /* like platform == PLATFORM_DONT_CARE */
break;
@ -172,8 +194,11 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
struct OUR_OSVERSIONINFOEXW osver;
BYTE majorCondition;
BYTE minorCondition;
BYTE buildCondition;
BYTE spMajorCondition;
BYTE spMinorCondition;
DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR;
typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN)
(struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG);
@ -190,6 +215,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_LESS_THAN:
majorCondition = VER_LESS;
minorCondition = VER_LESS;
buildCondition = VER_LESS;
spMajorCondition = VER_LESS_EQUAL;
spMinorCondition = VER_LESS_EQUAL;
break;
@ -197,6 +223,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_LESS_THAN_EQUAL:
majorCondition = VER_LESS_EQUAL;
minorCondition = VER_LESS_EQUAL;
buildCondition = VER_LESS_EQUAL;
spMajorCondition = VER_LESS_EQUAL;
spMinorCondition = VER_LESS_EQUAL;
break;
@ -204,6 +231,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_EQUAL:
majorCondition = VER_EQUAL;
minorCondition = VER_EQUAL;
buildCondition = VER_EQUAL;
spMajorCondition = VER_GREATER_EQUAL;
spMinorCondition = VER_GREATER_EQUAL;
break;
@ -211,6 +239,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_GREATER_THAN_EQUAL:
majorCondition = VER_GREATER_EQUAL;
minorCondition = VER_GREATER_EQUAL;
buildCondition = VER_GREATER_EQUAL;
spMajorCondition = VER_GREATER_EQUAL;
spMinorCondition = VER_GREATER_EQUAL;
break;
@ -218,6 +247,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
case VERSION_GREATER_THAN:
majorCondition = VER_GREATER;
minorCondition = VER_GREATER;
buildCondition = VER_GREATER;
spMajorCondition = VER_GREATER_EQUAL;
spMinorCondition = VER_GREATER_EQUAL;
break;
@ -230,6 +260,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
osver.dwOSVersionInfoSize = sizeof(osver);
osver.dwMajorVersion = majorVersion;
osver.dwMinorVersion = minorVersion;
osver.dwBuildNumber = buildVersion;
if(platform == PLATFORM_WINDOWS)
osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
else if(platform == PLATFORM_WINNT)
@ -239,26 +270,43 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
if(platform != PLATFORM_DONT_CARE)
if(platform != PLATFORM_DONT_CARE) {
cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
dwTypeMask |= VER_PLATFORMID;
}
/* Later versions of Windows have version functions that may not return the
real version of Windows unless the application is so manifested. We prefer
the real version always, so we use the Rtl variant of the function when
possible. Note though the function signatures have underlying fundamental
types that are the same, the return values are different. */
if(pRtlVerifyVersionInfo) {
matched = !pRtlVerifyVersionInfo(&osver,
(VER_MAJORVERSION | VER_MINORVERSION |
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
cm);
}
else {
matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
(VER_MAJORVERSION | VER_MINORVERSION |
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
cm);
if(pRtlVerifyVersionInfo)
matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
else
matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, dwTypeMask, cm);
/* Compare the build number separately. VerifyVersionInfo normally compares
major.minor in hierarchical order (eg 1.9 is less than 2.0) but does not
do the same for build (eg 1.9 build 222 is not less than 2.0 build 111).
Build comparison is only needed when build numbers are equal (eg 1.9 is
always less than 2.0 so build comparison is not needed). */
if(matched && buildVersion &&
(condition == VERSION_EQUAL ||
((condition == VERSION_GREATER_THAN_EQUAL ||
condition == VERSION_LESS_THAN_EQUAL) &&
curlx_verify_windows_version(majorVersion, minorVersion, 0,
platform, VERSION_EQUAL)))) {
cm = VerSetConditionMask(0, VER_BUILDNUMBER, buildCondition);
dwTypeMask = VER_BUILDNUMBER;
if(pRtlVerifyVersionInfo)
matched = !pRtlVerifyVersionInfo(&osver, dwTypeMask, cm);
else
matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver,
dwTypeMask, cm);
}
#endif
return matched;

View File

@ -45,6 +45,7 @@ typedef enum {
/* This is used to verify if we are running on a specific windows version */
bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion,
const unsigned int buildVersion,
const PlatformIdentifier platform,
const VersionCondition condition);

View File

@ -774,7 +774,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
"schannel: SSL/TLS connection with %s port %hu (step 1/3)",
hostname, conn->remote_port));
if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT,
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
/* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
algorithms that may not be supported by all servers. */
@ -788,7 +788,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") &&
curlx_verify_windows_version(6, 3, PLATFORM_WINNT,
curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL);
#else
BACKEND->use_alpn = false;
@ -805,7 +805,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#else
#ifdef HAS_MANUAL_VERIFY_API
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
BACKEND->use_manual_cred_validation = true;
}
@ -2045,7 +2045,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
*/
if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
!BACKEND->recv_sspi_close_notify) {
bool isWin2k = curlx_verify_windows_version(5, 0, PLATFORM_WINNT,
bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
VERSION_EQUAL);
if(isWin2k && sspi_status == SEC_E_OK)

View File

@ -355,7 +355,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
DWORD i;
/* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
if(curlx_verify_windows_version(6, 2, PLATFORM_WINNT,
if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
/* CertGetNameString will provide the 8-bit character string without
@ -597,7 +597,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
* trusted certificates. This is only supported on Windows 7+.
*/
if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) {
if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN)) {
failf(data, "schannel: this version of Windows is too old to support "
"certificate verification via CA bundle file.");
result = CURLE_SSL_CACERT_BADFILE;

View File

@ -768,7 +768,7 @@ CURLcode win32_init(void)
{
/* curlx_verify_windows_version must be called during init at least once
because it has its own initialization routine. */
if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL))
tool_isVistaOrGreater = true;
else