c++winhttp

Why would applications fail on calls to WinHttpOpen with WINHTTP_FLAG_SECURE_DEFAULTS set on Windows Server 2019 and older?


Given a simple test application that simply calls WinHttpOpen() as follows and does nothing else:

WinHttpOpen(userAgent, WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC | WINHTTP_FLAG_SECURE_DEFAULTS);

I've noticed that the above call fails with error code 87 (ERROR_INVALID_PARAMETER) on Windows Server 2019 (Datacenter or Standard) and older machines (also tested on Windows Server 2016 Standard). It works as expected on Windows 10 Enterprise and Windows Server 2022 Datacenter.

Removing the WINHTTP_FLAG_SECURE_DEFAULTS flag makes the issue go away. As this flag enforces TLS 1.2 or newer, it seems likely that there's some OS-level configuration needed. (Note that this doesn't impact SChannel use of TLS 1.2).

Is there some registry configuration, feature, or patch that is generally missing on Windows Server 2019 and older installations?


Solution

  • WINHTTP_FLAG_SECURE_DEFAULTS simply didn't exist on older systems, so if you try to use it on them, they won't know what that flag means, and so they will fail. This is even called out explicitly in Microsoft's documentation:

    Game Development Kit (GDK) | Overviews and how-to | Networking | Web requests | WinHTTP overview

    The WINHTTP_FLAG_SECURE_DEFAULTS flag is a new flag that's specifically designed to help Microsoft Game Development Kit (GDK) titles to adhere to the security best practices by setting the recommended secure connection behavior. It's available on Xbox One consoles and will be available on Windows PC in a future Windows OS update. Trying to pass WINHTTP_FLAG_SECURE_DEFAULTS on existing Windows OS versions results in an invalid parameter failure. This flag has a significant side effect—it forces WinHTTP into the asynchronous mode because this flag implicitly includes the WINHTTP_FLAG_ASYNC flag. On Windows PC OS versions that don't support this flag, you should pass WINHTTP_FLAG_ASYNC instead to minimize differences in the remainder of your WinHTTP implementation.