]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
version_win32: Check build number and platform id
authorWyatt O'Day <wyatt@wyday.com>
Thu, 7 Oct 2021 10:58:39 +0000 (06:58 -0400)
committerJay Satiro <raysatiro@yahoo.com>
Thu, 2 Dec 2021 08:39:14 +0000 (03:39 -0500)
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

lib/connect.c
lib/curl_sspi.c
lib/system_win32.c
lib/version_win32.c
lib/version_win32.h
lib/vtls/schannel.c
lib/vtls/schannel_verify.c
src/tool_doswin.c

index 94490805ad58bf7791abb63d38cb2a5fd471a15c..c573875496843bfb4665d25a0e48634db0093d4b 100644 (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
index 06841ddec691fd7cd27e3367ecc1bd82c9234931..29a98bb32b9f6d5bc248b229d6b5c853fc66f546 100644 (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"));
index d4e194831fc0f253c05e435aa71b75a627995906..9a6dd9cef6f6d490decefa8e95c712197e32b3ab 100644 (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;
   }
index 2f845413ccb1832c9b0b62a4bc8baa72a5bf857a..79a2aa6ab456ba6bef319cb5961a279e074ce26f 100644 (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;
index 9b1bd88874e4418c4ba715b3d79bea71b8ed9085..f5bfef426bbff247c51a9348cd21a1db232cac6b 100644 (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);
 
index 44c59e7796b4c3a647ecf2d774c7a97e2e9742da..5d18037e8a87e65b17a513e1cabba60bfe2be16a 100644 (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)
index 1b283d0453bcd65e825df681a85ef54530b5884a..4966cd4945616210875ccd485fec4c8274a7d3c4 100644 (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;
index 1ad9cddc3f8f0d734e98ee7a0e38584a2b33ff0f..2390fab7f8d7a347849991bb885a5068169ff07c 100644 (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