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; static int detectOsState = DETECT_OS_NONE;
if(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)) VERSION_GREATER_THAN_EQUAL))
detectOsState = DETECT_OS_VISTA_OR_LATER; detectOsState = DETECT_OS_VISTA_OR_LATER;
else else

View File

@ -83,7 +83,7 @@ CURLcode Curl_sspi_global_init(void)
* have both these DLLs (security.dll forwards calls to secur32.dll) */ * have both these DLLs (security.dll forwards calls to secur32.dll) */
/* Load SSPI dll into the address space of the calling process */ /* 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")); s_hSecDll = Curl_load_library(TEXT("security.dll"));
else else
s_hSecDll = Curl_load_library(TEXT("secur32.dll")); 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 /* curlx_verify_windows_version must be called during init at least once
because it has its own initialization routine. */ 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)) { VERSION_GREATER_THAN_EQUAL)) {
Curl_isVistaOrGreater = TRUE; Curl_isVistaOrGreater = TRUE;
} }

View File

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

View File

@ -45,6 +45,7 @@ typedef enum {
/* This is used to verify if we are running on a specific windows version */ /* This is used to verify if we are running on a specific windows version */
bool curlx_verify_windows_version(const unsigned int majorVersion, bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion, const unsigned int minorVersion,
const unsigned int buildVersion,
const PlatformIdentifier platform, const PlatformIdentifier platform,
const VersionCondition condition); 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)", "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
hostname, conn->remote_port)); 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)) { VERSION_LESS_THAN_EQUAL)) {
/* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
algorithms that may not be supported by all servers. */ 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 && BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")), !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") && "wine_get_version") &&
curlx_verify_windows_version(6, 3, PLATFORM_WINNT, curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL); VERSION_GREATER_THAN_EQUAL);
#else #else
BACKEND->use_alpn = false; BACKEND->use_alpn = false;
@ -805,7 +805,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#else #else
#ifdef HAS_MANUAL_VERIFY_API #ifdef HAS_MANUAL_VERIFY_API
if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) { 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)) { VERSION_GREATER_THAN_EQUAL)) {
BACKEND->use_manual_cred_validation = true; 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 && if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
!BACKEND->recv_sspi_close_notify) { !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); VERSION_EQUAL);
if(isWin2k && sspi_status == SEC_E_OK) 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; DWORD i;
/* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */ /* 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)) { VERSION_GREATER_THAN_EQUAL)) {
#ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
/* CertGetNameString will provide the 8-bit character string without /* 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+. * 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 " failf(data, "schannel: this version of Windows is too old to support "
"certificate verification via CA bundle file."); "certificate verification via CA bundle file.");
result = CURLE_SSL_CACERT_BADFILE; 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 /* curlx_verify_windows_version must be called during init at least once
because it has its own initialization routine. */ 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)) VERSION_GREATER_THAN_EQUAL))
tool_isVistaOrGreater = true; tool_isVistaOrGreater = true;
else else