protonscr

Regression regarding SSL connections in .NET 5+ applications

wineclosed
ValveSoftware/wine#150 · opened 2022-05-23 by goaaats · updated 2022-06-05 · 3 comments · github
Ggoaaats 2022-05-23 github

A change in Proton currently causes SEC_E_INTERNAL_ERROR in AcquireCredentialsHandleW while calling get_cred when attempting any SSL connection via the built-in HttpClient class in .NET 5+ applications while the OS version is set to win10.

It calls get_cred with a version of 5, while SCHANNEL_CRED_VERSION is defined as 4 globally. This causes a fail-fast in the linked switch case.

With win10 OS version:

1008.921365:0020:013c:trace:secur32:schan_AcquireCredentialsHandleW ((null), L"Microsoft Unified Security Protocol Provider", 0x00000002, 0000000000000000, 00000000262BDBF0, 0000000000000000, 0000000000000000, 0000000004F8EAC0, 00000000262BD828)
1008.921393:0020:013c:trace:secur32:schan_AcquireClientCredentials schanCred 00000000262BDBF0, phCredential 0000000004F8EAC0, ptsExpiry 00000000262BD828
1008.921396:0020:013c:trace:secur32:get_cert dwVersion = 5
1008.921398:0020:013c:trace:secur32:get_cert cCreds = 0
1008.921400:0020:013c:trace:secur32:get_cert paCred = 0000000000000000
1008.921401:0020:013c:trace:secur32:get_cert hRootStore = 0000000000000000
1008.921403:0020:013c:trace:secur32:get_cert cMappers = 0
1008.921405:0020:013c:trace:secur32:get_cert cSupportedAlgs = 0:
1008.921407:0020:013c:trace:secur32:get_cert grbitEnabledProtocols = 00000000
1008.921408:0020:013c:trace:secur32:get_cert dwMinimumCipherStrength = 0
1008.921410:0020:013c:trace:secur32:get_cert dwMaximumCipherStrength = 0
1008.921412:0020:013c:trace:secur32:get_cert dwSessionLifespan = 0
1008.921414:0020:013c:trace:secur32:get_cert dwFlags = 00000000
1008.921415:0020:013c:trace:secur32:get_cert dwCredFormat = 0
1008.921417:0020:013c:Ret  secur32.AcquireCredentialsHandleW() retval=80090304 ret=e0b76c19

With win7 OS version:

500.058:00fc:0130:trace:secur32:schan_AcquireCredentialsHandleW ((null), L"Microsoft Unified Security Protocol Provider", 0x00000002, 0000000000000000, 000000002444DAA0, 0000000000000000, 0000000000000000, 0000000002750AB8, 000000002444D708)
500.058:00fc:0130:trace:secur32:schan_AcquireClientCredentials schanCred 000000002444DAA0, phCredential 0000000002750AB8, ptsExpiry 000000002444D708
500.058:00fc:0130:trace:secur32:get_cert dwVersion = 4
500.058:00fc:0130:trace:secur32:get_cert cCreds = 0
500.058:00fc:0130:trace:secur32:get_cert paCred = 0000000000000000
500.058:00fc:0130:trace:secur32:get_cert hRootStore = 0000000000000000
500.058:00fc:0130:trace:secur32:get_cert cMappers = 0
500.058:00fc:0130:trace:secur32:get_cert cSupportedAlgs = 0:
500.058:00fc:0130:trace:secur32:get_cert grbitEnabledProtocols = 00000000
500.058:00fc:0130:trace:secur32:get_cert dwMinimumCipherStrength = 0
500.058:00fc:0130:trace:secur32:get_cert dwMaximumCipherStrength = 0
500.058:00fc:0130:trace:secur32:get_cert dwSessionLifespan = 0
500.058:00fc:0130:trace:secur32:get_cert dwFlags = 00600018
500.058:00fc:0130:trace:secur32:get_cert dwCredFormat = 0

Manually switching the version to win7 via winecfg or protontricks is enough to solve the issue.

Curiously, SCHANNEL_CRED_VERSION is defined as 4 in the .NET sources as well and I can't spot any place where this is changed. Note that dwFlags is also zero'd out in the win10 example.

Reproduction

I have created a small reproduction program that you can build with cd NetHttpsTest && dotnet publish if you have the dotnet 6 SDK installed. The resulting files in NetHttpsTest\bin\Debug\net6.0\win-x64\publish will be self-contained Windows binaries that do not need a runtime in the wineprefix. You don't need a Windows machine to do this. In my testing, any HTTPS URL seems to cause the issue, e.g. https://google.com. I've tested this in the current Proton Experimental.
NetHttpsTest.zip (prebuilt)

You should see this stack trace when the connection fails:

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> System.ComponentModel.Win32Exception (0x80090304): Unknown error (0x80090304)
   at System.Net.SSPIWrapper.AcquireCredentialsHandle(ISSPIInterface secModule, String package, CredentialUse intent, SCH_CREDENTIALS* scc)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandle(CredentialUse credUsage, SCH_CREDENTIALS* secureCredential)
   at System.Net.Security.SslStreamPal.AcquireCredentialsHandleSchCredentials(SslStreamCertificateContext certificateContext, SslProtocols protocols, EncryptionPolicy policy, Bool
ean isServer)
[...]

The issue does not exist in the tagged upstream wine-7.9 release. It currently affects a modding toolkit I am maintaining, which is injected into a game, but I'm aware of at least one Steam game that is affected by this issue as well: https://github.com/ValveSoftware/Proton/issues/4940#issuecomment-1059781132

If I can do anything to help with troubleshooting this, or if this is better reported elsewhere, please let me know.

Aaeikum 2022-05-23 github

You said:

The issue does not exist in the tagged upstream wine-7.9 release.

Which is a bit interesting. That switch statement does exist upstream: https://source.winehq.org/git/wine.git/blob/wine-7.9:/dlls/secur32/schannel.c#l336 and has existed since 2006. I wonder what is different between Proton and upstream?

Thanks for the report, I'll ask our QA to reproduce the S&box issue and have a dev take a look.

Ggoaaats 2022-05-23 github

After some more testing, it turns out that if you switch the version in the prefix once, this issue is fixed for good - even switching back to win10 won't bring it back, so this is only reproducible on a completely fresh prefix as created by Proton.

This makes me think that this is an issue with defaults/the patches that were introduced to make Windows 10 the default version in loader/wine.inf.in.

Thanks for passing it on!

Ggoaaats 2022-06-05 github

This seems to be fixed in the latest Proton Experimental, thank you very much.

Proton versions

Upstream links

Error codes