dotnet / docs

This repository contains .NET Documentation.
https://learn.microsoft.com/dotnet
Creative Commons Attribution 4.0 International
4.21k stars 5.86k forks source link

Transport Layer Security (TLS) best practices with the .NET Framework #4675

Open Rick-Anderson opened 6 years ago

Rick-Anderson commented 6 years ago

Use this issue to ask questions about the Transport Layer Security (TLS) best practices with the .NET Framework document.

RamanBut-Husaim commented 6 years ago

@Rick-Anderson @mairaw hello.

Would like to clarify the information present in the following section - https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#for-wcf-using-net-framework-35---452-using-tcp-transport-security-with-certificate-credentials.

These versions of the WCF framework are hardcoded to use values SSL 3.0 and TLS 1.0. These values cannot be changed. You must update and retarget to NET Framework 4.6 or later versions to use TLS 1.1 and 1.2.

Do I understand correctly that it covers the case with basic http binding that uses certificate for authentication on the transport level?

<binding name="some-binding" >
  <security mode="Transport">
    <transport clientCredentialType="Certificate" />
  </security>
</binding>

Thanks.

mconnew commented 6 years ago

Hi @RamanBut-Husaim. The section which you quoted only applies to using the TCP transport in WCF. For the HTTP transport with a WCF client doesn't do anything specific. Internally we use HttpWebRequest so we will just have the behavior that HttpWebRequest will have. For the HTTP transport with a WCF client, we have the behavior that the OS components IIS or HTTP.SYS are configured to use.

RamanBut-Husaim commented 6 years ago

@mconnew Understood. Thanks a lot for the quick reply!

bjorncoltof commented 6 years ago

Hi @Rick-Anderson, the article covers enabling TLS 1.2 quite well, is it possible to extend it with information about how to enforce TLS 1.2?

karelz commented 6 years ago

@bjorncoltof I don't believe we have mechanisms to forbid certain protocol versions via app-wide/machine-wide configuration (incl. registry). Maybe the OS has something like that?

cc @davidsh

davidsh commented 6 years ago

Maybe the OS has something like that?

Yes, Windows OS has registry keys you can set to enable/disable various TLS protocol versions.

See: https://docs.microsoft.com/en-us/windows-server/security/tls/tls-registry-settings

For example:

Registry path: HKLM SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols

To disable the TLS 1.0 protocol, create an Enabled entry in the appropriate subkey. This entry does not exist in the registry by default. After you have created the entry, change the DWORD value to 0. To enable the protocol, change the DWORD value to 1.

Subkey | Description
Client | Controls the use of TLS 1.0 on the TLS client.
Server | Controls the use of TLS 1.0 on the TLS server.
DisabledByDefault | Flag to disable TLS 1.0 by default.
blowdart commented 6 years ago

https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/manage-ssl-protocols-in-ad-fs also has some powershell should you want to avoid the regedit.

coolzsunil commented 6 years ago

I am a little confused after reading your article - https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#if-your-app-targets-a-net-framework-version-earlier-than-47

In the section - If your app targets a .NET Framework version earlier than 4.7 - For .NET Framework 3.5 - 4.5.1 and not WCF

it is mentioned - Set the SchUseStrongCrypto and SystemDefaultTlsVersions registry keys to 1

As per our tests with sample applications, we do not require SystemDefaultTlsVersions for going TLS 1.2. The presence of SchUseStrongCrypto is good enough for any apps which are targeting .NET 4.0 - 4.6.2 to move to TLS 1.2.

The explanation of SystemDefaultTlsVersions in the same documents, only mentions the cases, when 4.7 is installed on the system. For all other cases, where the machine has 4.5.2 to 4.6.2, but with apps targeting .NET 4.0 - 4.6.2, the presence of SchUseStrongCrypto is the only entry, we require. Our understanding is also mentioned here - https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/manage-ssl-protocols-in-ad-fs#enabling-strong-authentication-for-net-applications

Can you please confirm the correct one?

Regards, Sunil Bhaskar

davidsh commented 6 years ago

Can you please confirm the correct one?

The difference between SchUseStrongCrypto and SystemDefaultTlsVersions is subtle. Both of them will indeed add Tls1.1 and Tls1.2 to the set of possible protocols. And doing so implies that the strongest protocol (in this case Tls1.2) would be offered first to a server. Assuming the server supported Tls1.2, the end result would be Tls1.2.

The difference between those two registry entries is as follows. SchUseStrongCrypto will always drop Ssl3.0 as well as any cipher suites from Tls1.0 et. al. that are considered insecure such as RC4. SchUseStrongCrypto will also set the default ServicePointManager.SecurityProtocol property to use "Tls1.0 | Tls 1.1 | Tls1.2" as the default. However, note that this list is fixed.

Using SystemDefaultTlsVersions, on the other hand, causes the same ServicePointManager.SecurityProtocol property to use a default of SecurityProtocolType.SystemDefault. That means that the operating system will select the set of TLS protocols for the default set. And this default set will change over time depending on the OS version. For example, as the OS version moves forward in the future, TLS 1.3 will be added and other protocols will be removed.

See the matrix of OS versions TLS protocols here: https://support.microsoft.com/en-us/help/3154518/support-for-tls-system-default-versions-included-in-the-net-framework

The guidance given in our documentation is that for new code the recommendation is to use patterns such as SystemDefaultTlsVersions to let the OS make the best decision. For new .NET Framework applications targeting 4.7 and later, these registry keys are not needed and the equivalent "SystemDefault" values are used.

coolzsunil commented 6 years ago

@davidsh The move to use SystemDefaultTlsVersions is not comprehensive. An application has a single config file. And if we set the application config to use System default, it will fail on Windows 7 and Windows 2008R2, where TLS 1.0 is the default protocol. This makes it difficult to support multiple operating system using a single config file.

Also, do you know whether the support for SystemDefaultTlsVersions is there in frameworks 4.0 - 4.6.2. I do not see any documentation which points to a Windows update, which added support for these.

davidsh commented 6 years ago

Also, do you know whether the support for SystemDefaultTlsVersions is there in frameworks 4.0 - 4.6.2. I do not see any documentation which points to a Windows update, which added support for these.

SystemDefaultTlsVersions is only supported in .NET 4.7 and above.

marcroussy commented 6 years ago

I have a scenario with a Windows 7 machine with 4.7.1 installed and a WPF application that targets 4.7.1. The app isn't setting the SystemDefaultTlsVersions, and therefore should be using the OS default (which should be TLS 1.0, since 1.1 and 1.2 aren't enabled by default on Win7).

The endpoint I'm calling from the WPF app has TLS1, 1.1, and 1.2 enabled.

I'm getting a connection error in the WPF app unless I enable TLS 1.2 in Windows 7. Is this the expected behaviour for WPF apps running 4.7.1?

davidsh commented 6 years ago

I'm getting a connection error in the WPF app unless I enable TLS 1.2 in Windows 7. Is this the expected behaviour for WPF apps running 4.7.1?

Yes, unfortunately.

If your app is targeting .NET 4.7.x, then effectively you are using 'SystemDefaultTlsVersions' regardless of you setting the registry key. The behavior default is ON when targeting .NET 4.7.x.

On Windows 7 / Windows Server 2008 R2, the default set of TLS protocols in the OS doesn't include TLS 1.1 nor 1.2. So, the highest you will get then is TLS 1.0.

But since your service only allows TLS 1.1 and TLS 1.2, you will thus be unable to connect with your client.

The workaround in this case (if you need to run on Windows 7 / Windows Server 2008 R2) would be manually configure the TLS versions using ServicePointManager properties. And also make sure that the applicable Windows updates are used on Windows 7 to enable TLS 1.1 and 1.2.

mjkkirschner commented 5 years ago

Hi @davidsh - My group works on an assembly which might be used in various contexts (some we don't control). This assembly makes rest calls to a server we would like to limit to accepting tls1.2 > connections. When referenced by other applications we would like to avoid hard coding TLS 1.2 and effecting future protocols for the referencing application.

We are currently limited to targeting .net 4.5.2 in our assembly - but the referencing application may be a more recent .net version. Is there a way to check what protocols are currently supported by the user's machine before setting:

ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

something like

if(!(TLS1.2_Enabled)){
 ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
}

Does this functionality exist in .net?

ngzhiying commented 5 years ago

@Rick-Anderson @mairaw hello.

Would like to clarify the information present in the following section - https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#for-wcf-using-net-framework-35---452-using-tcp-transport-security-with-certificate-credentials.

These versions of the WCF framework are hardcoded to use values SSL 3.0 and TLS 1.0. These values cannot be changed. You must update and retarget to NET Framework 4.6 or later versions to use TLS 1.1 and 1.2.

What about WCF frameworks (3.5 to 4.5.2) that are using TCP transport security with windows authentication? This seems to be left out in the article - Does the hardcoding to use SSL3.0 and TLS 1.0 still apply?

davidsh commented 5 years ago

Is there a way to check what protocols are currently supported by the user's machine before setting. Does this functionality exist in .net?

Not really. Support for the various TLS protocols depends on a number of factors including .NET version and Windows OS version. And "support" could mean different things, i.e. "Is TLS 1.2 the default protocol" or "Can TLS 1.2 be used if explicitly specified etc.".

cc: @karelz

henkmeulekamp commented 5 years ago

In the section If your app targets .NET Framework 4.7 or later versions

For WCF Message Security with certificate credentials .NET Framework 4.7 and later versions by default uses the protocol specified in the SecurityProtocol property. When the AppContextSwitch Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols is set to true, WCF chooses the best protocol, up to TLS 1.0.

What does this mean:

WCF chooses the best protocol, up to TLS 1.0.

So first 1.2, then 1.1 then finally 1.0 is tried?

Or maximum TLS 1.0 and above versions 1.1 and 1.2 are not tried?

henkmeulekamp commented 5 years ago

Next question, from unittesting 4.7.0 code on a client machine (win10) it looks like WCF client code targeting 4.7.0 still uses ssl3, tls as default. You need to target 4.7.1 to be able to be able to use tls 1.2 when using the wcf generated client stub to access a TLS 1.2 only service.?

Is this assumption correct or do we need to have a better look at our code why it keeps defaulting System.Net.ServicePointManager.SecurityProtocol using ssl3, tls?

karelz commented 5 years ago

@henkmeulekamp

What does this mean:

WCF chooses the best protocol, up to TLS 1.0.

So first 1.2, then 1.1 then finally 1.0 is tried? Or maximum TLS 1.0 and above versions 1.1 and 1.2 are not tried?

It means TLS 1.0 and lower. In other words, do not set the AppContext switch to true unless you have really good reasons and you know what you're doing - see its description.

@mconnew can you look at the second question? The doc is a bit confusing also to me - this section talks about both 4.7.1 and 4.7 - which one is it? https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#for-wcf-tcp-transport-using-transport-security-with-certificate-credentials

gaborlaczo commented 5 years ago

I'm missing information about "If your app targets a .NET Framework version earlier than 4.7" and using WCF without certificate credentials.

I wrote a very simple test application targeting .net framework 4.0, which just simple writes the default value of "ServicePointManager.SecurityProtocol". In case of a computer runs .net framework 4.7 and the registry also set for enabling all TLS versions and SSL was disabled the result was:

Tls, Tls11, Tls12

So in my case I don't see that I should rebuild all of my applications targeting the new framework.

Actually this is a little confusing for me how the build target could affect the application runtime. Does the runtime check the build target version and modify its behaviour depends on it?

Could you point to this in reference source?

davidsh commented 5 years ago

Does the runtime check the build target version and modify its behaviour depends on it?

Yes. We have code in the .NET Framework runtime that checks the build target version (called the Target Framework Moniker, TFM).

The code logic is complicated because in addition to checking that we also check a bunch of other registry keys, AppContext values etc.

Some of the logic for that is here: https://github.com/Microsoft/referencesource/blob/master/System/net/System/Net/ServicePointManager.cs

apiliuhin commented 5 years ago

Hi @Rick-Anderson @mairaw

would like to clarify if there is a possibility to set up different protocols in the client app.config to use for example: 1) url 1 set to use TLS 1.2 2) url 2 set to Ssl3 (Ssl3 only)

using .NET Framework 4.5.2

Thanks.

davidsh commented 5 years ago

would like to clarify if there is a possibility to set up different protocols in the client app.config to use for example: url 1 set to use TLS 1.2 url 2 set to Ssl3 (Ssl3 only) using .NET Framework 4.5.2

This is not possible. There are no settings at per-request granularity for that.

It you need that level of control you will have to do it in code.

gaborlaczo commented 5 years ago

Some of the logic for that is here: https://github.com/Microsoft/referencesource/blob/master/System/net/System/Net/ServicePointManager.cs

Thanks for your fast answer. Actually we did a lot view on that code before I askeed my question earlier and I still don't find where and what role here the TFM does.

We got this exception before TLS 1.2 was disabled by default in registry(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2), but after this was set to 0 it became working.

System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority '...'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.

   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---

Server stack trace:

   at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)

   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)

   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)

   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)

   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)

   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
davidsh commented 5 years ago

Server stack trace: at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)

@mconnew Can you help comment on this WCF stack trace?

mconnew commented 5 years ago

Sorry, I missed a couple of questions in this issue previously. @henkmeulekamp, in your question here, the section you are quoting is about using certificate authentication when using message security. In that scenario, we just use whatever value is set in ServicePointManager.SecurityProtocols as we didn't have a public class that we could expose an explicit property on. This isn't not related to the TLS protocol used for HTTPS but is a different usage of the TLS protocol used by message security.
In response to the question from @Karelz here. The section linked is talking about the WCF TCP transport (net.tcp) using certificate authentication (as opposed to windows authentication). We have different behavior on 4.7 and 4.7.1. On 4.7 our behavior is not dependent on which version you target and we default to TLS1.2, TLS1.1 and TLS1.0 all being allowed. Starting from 4.7.1, we made a change based on which version of the framework you are targeting. If you target 4.7.1 or above, the default is now SslProtocols.None which means you will get the OS default. If you target 4.7 or earlier, but are running on 4.7.1 or later, you will get the 4.7 behavior of the default being TLS1.2, TLS1.1 and TLS1.0.
For HTTPS, we don't do anything special and just let HttpWebRequest do whatever has been configured.
@davidsh, that call stack is where we process any exception thrown from calling HttpWebRequest.GetResponse(). The specific WCF exception message is used when WebException.Status has a value of WebExceptionStatus.SecureChannelFailure. If disabling TLS1.2 made things work, I suspect really old certificates are being used. TLS1.2 does NOT work if your certificate has been signed using md5. In this scenario, when both ends are configured to use TLS1.2 if available, they negotiate TLS1.2 but then can't complete the handshake because the certificate isn't usable. Disabling TLS1.2 on one end causes TLS1.1 to be negotiated instead and now the certificate can be used. That's my best guess to what's happening.

yahiac-aug commented 5 years ago

Hello! Can someone help me? I made this: https://support.microsoft.com/en-us/help/3206898/enabling-iis-manager-and-web-deploy-after-disabling-ssl3-and-tls-1-0 but i still can't use iis manager after disabling tls 1.0 :( (on windows 2008 r2 sp1 core) note: they talking about this patch: windows6.1-kb3154518-x64 but if i try to install it, i have the message: "the update is not applicable to your computer"

blacklion9279 commented 5 years ago

The doc is little confusing. Can you please clarify if .net app running on .net framework 4.6.2 and targeting 4.6.2, will it choose strongest available TLS version i.e. TLS 1.2 without a) specifically configuring anything in web.config under < AppContext> and b) setting SchUseStrongCrypto or c changing any registry keys for Windows Server 2008 R2 or Windows Server 2012 R2 or Windows Server 2016?

davidsh commented 5 years ago

@blacklion9279

Can you please clarify if .net app running on .net framework 4.6.2 and targeting 4.6.2, will it choose strongest available TLS version i.e. TLS 1.2 without a) specifically configuring anything in web.config under < AppContext> and b) setting SchUseStrongCrypto or c changing any registry keys for Windows Server 2008 R2 or Windows Server 2012 R2 or Windows Server 2016?

The short answer is no. If you're targeting less than .NET Framework 4.7, you must follow the steps in the document to ensure you negotiate TLS 1.2 by default.

If your app targets a .NET Framework version earlier than 4.7
Audit your code to verify you're not setting a specific TLS or SSL version using the following sections:

For .NET Framework 4.6 - 4.6.2 and not WCF
Set the DontEnableSystemDefaultTlsVersions AppContext switch to false.
See Configuring security via AppContext switches:
https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#configuring-security-via-appcontext-switches
blacklion9279 commented 5 years ago

@blacklion9279

Can you please clarify if .net app running on .net framework 4.6.2 and targeting 4.6.2, will it choose strongest available TLS version i.e. TLS 1.2 without a) specifically configuring anything in web.config under < AppContext> and b) setting SchUseStrongCrypto or c changing any registry keys for Windows Server 2008 R2 or Windows Server 2012 R2 or Windows Server 2016?

The short answer is no. If you're targeting less than .NET Framework 4.7, you must follow the steps in the document to ensure you negotiate TLS 1.2 by default.

If your app targets a .NET Framework version earlier than 4.7
Audit your code to verify you're not setting a specific TLS or SSL version using the following sections:

For .NET Framework 4.6 - 4.6.2 and not WCF
Set the DontEnableSystemDefaultTlsVersions AppContext switch to false.
See Configuring security via AppContext switches:
https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#configuring-security-via-appcontext-switches

Ok. Got it. Thanks for clarifying that. Follow up question - What's expected behavior on net framework 4.6.2 not WCF, when DontEnableSystemDefaultTlsVersions is NOT yet set to false?

In .net app, there is not specific protocol forced and let's say TLS 1.0, 1.1 and 1.2 protocols are available.

davidsh commented 5 years ago

Ok. Got it. Thanks for clarifying that. Follow up question - What's expected behavior on net framework 4.6.2 not WCF, when DontEnableSystemDefaultTlsVersions is NOT yet set to false? In .net app, there is not specific protocol forced and let's say TLS 1.0, 1.1 and 1.2 protocols are available.

If you don't set any of the registry keys or AppContext switches discussed in this document, then the default for applications targeting .NET Framework 4.6.2 will be the current default for ServicePointManager.SecurityProtocol. And that default value is "Ssl30 | Tls10". So, that will result in your application trying to negotiate at most TLS 1.0 protocol with a server.

RamanJindal commented 5 years ago

@Rick-Anderson @mairaw @mconnew

Hello,

Would like to clarify the information present in the following section - https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#for-wcf-using-net-framework-35---452-using-tcp-transport-security-with-certificate-credentials.

What about WCF frameworks (3.5 to 4.5.2) that are using TCP transport security with Windows authentication? This seems to be left out in the article - Does the hardcoding to use SSL3.0 and TLS 1.0 still apply?

For a WCF client with configuration as: binding=netTcp, security=transport, clientCredentialType=windows and targeting .net = 4.5.2, will it be required to upgrade client to .NET 4.6 or specifying ServicePointManager.SecurityProtocol as TLS1.2 before service call will work?

mconnew commented 5 years ago

The TCP transport only uses TLS/SSL when certificate credentials are being used. When using Windows credentials with the TCP transport you can ignore this document as we use NegotiateStream to secure the connection.
If you are using any of the HTTP bindings and your endpoint is using HTTPS, then this document still applies as usage of Windows credentials over HTTP are for authentication only and aren't used to secure the actual connection. With HTTPS, the transport is always secured using TLS/SSL regardless of credential type. This is not the case with the TCP transport.

RamanJindal commented 5 years ago

The TCP transport only uses TLS/SSL when certificate credentials are being used. When using Windows credentials with the TCP transport you can ignore this document as we use NegotiateStream to secure the connection. If you are using any of the HTTP bindings and your endpoint is using HTTPS, then this document still applies as usage of Windows credentials over HTTP are for authentication only and aren't used to secure the actual connection. With HTTPS, the transport is always secured using TLS/SSL regardless of credential type. This is not the case with the TCP transport.

Thanks for the clarification!!

RamanJindal commented 5 years ago

Ok. Got it. Thanks for clarifying that. Follow up question - What's expected behavior on net framework 4.6.2 not WCF, when DontEnableSystemDefaultTlsVersions is NOT yet set to false? In .net app, there is not specific protocol forced and let's say TLS 1.0, 1.1 and 1.2 protocols are available.

If you don't set any of the registry keys or AppContext switches discussed in this document, then the default for applications targeting .NET Framework 4.6.2 will be the current default for ServicePointManager.SecurityProtocol. And that default value is "Ssl30 | Tls10". So, that will result in your application trying to negotiate at most TLS 1.0 protocol with a server.

@davidsh - What you mentioned above is opposite to what has been documented here https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#schusestrongcrypto

If your app targets .NET Framework 4.6 or later versions, this key defaults to a value of 1

Can you please clarify?

abhijitsbhopale commented 5 years ago

What could be a way to know which TLS protocol version is being used in the nettcp client-server communication for a particular session? In service call, it is possible to print supported protocols using System.Net.ServicePointManager.SecurityProtocol but information about the actual version used in the communication/session is missing. Have posted question at StackOverflow as well but no luck.

karelz commented 5 years ago

@abhijitsbhopale I don't think it is possible to do in .NET.

abhijitsbhopale commented 5 years ago

@karelz Thank you for the response. Is there any way by capturing the packets over the network? I tried with Wireshark & RawCap but the encrypted packets don't give any clue.

abhijitsbhopale commented 5 years ago

Hello All, Came across a strange problem with sslProtocols settings with netTcpBinding. I have set below configuration inside binding tag,

<security mode="Transport">
         <transport clientCredentialType="Windows"
                    protectionLevel="EncryptAndSign"
                    sslProtocols="None"></transport>
</security>

It works on Windows 7 and 10 but on Windows Server 2008 R2 SP1, same application throws an exception saying "Unrecognized attribute 'sslProtocols'. If I remove sslProtocols="None" from configuration it works on Windows Server 2008 as well. How it is possible to have OS-sepcific attribute?

Using .net framework 4.5.1 and do not want to provide OS-specific config files. Please help me to solve this. The same problem is with sslProtocols="tls1" etc. as the problem is with attribute and not with value.

davidsh commented 5 years ago

What could be a way to know which TLS protocol version is being used in the nettcp client-server communication for a particular session? In service call, it is possible to print supported protocols using System.Net.ServicePointManager.SecurityProtocol but information about the actual version used in the communication/session is missing. Have posted question at StackOverflow as well but no luck.

There is no programmatic (API) way of getting the final TLS protocol version negotiated. However, you can easily see this in WireShark. Just look for the "TLS Server Hello" frame in WireShark. Here is the example when I connect to https://www.microsoft.com/

You can see that it shows I connected using TLS 1.2. And I'm using HTTP/2 protocol as well (that is shown in the ALPN Protocol field).

image

davidsh commented 5 years ago

@RamanJindal

@davidsh - What you mentioned above is opposite to what has been documented here https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#schusestrongcrypto If your app targets .NET Framework 4.6 or later versions, this key defaults to a value of 1 Can you please clarify?

There is a subtle difference between SchUseStrongCrytpto and DontEnableSystemDefaultTlsVersions

In general, setting "UseStrongCrypto" will make sure that Ssl30 is not included as well as set the default to "Tls1 | Tls11 | Tls12". However, this is still specifying a specific set of TLS protocol versions.

When you have the "SystemDefaultTlsVersions" activated, you end up with something better. Instead of providing a hard-coded default value for ServicePointManager.SecurityProtocol, you end up getting the SystemDefault setting. That allows the TLS protocol version to use the strongest OS default. Currently that is TLS 1.2. But in the future, new versions of Windows OS will change that to include TLS 1.3 etc.

abhijitsbhopale commented 5 years ago

@davidsh ServerHello, ALPN etc. on Wireshark works with Https communication, not net TCP. There is no ServerHello or ClientHello visible for TCP on Wireshark or any other sniffing tool.

davidsh commented 5 years ago

@davidsh ServerHello, ALPN etc. on Wireshark works with Https communication, not net TCP. There is no ServerHello or ClientHello visible for TCP on Wireshark or any other sniffing tool.

HTTPS communication at the lowest layer is simply TLS on a TCP connection.

"net TCP" is still a TCP connection at the lowest layer. And then it uses TLS on top of that. It stays a binary protocol after that as compared to HTTP protocol on top of TLS (which is HTTPS).

WireShark should still show the TCP connection traffic as well as the TLS negotiation. Perhaps it is having trouble parsing the ethernet frames because it is using a nonstandard port. Can you show a screenshot showing what you see when you try to use WireShark on that network traffic?

ShaunLoganOracle commented 5 years ago

I have a VSTO add-in for Excel (C#), that targets .NET 4.7. It uses HttpWebRequest (not WCF). I observe the following when I do not specify a value for ServicePointManager.SecurityProtocol (as recommended by the doc): 1) On Windows 7 and Windows 10 with .NET 4.7.2, the client HTTPS handshake offers TLS1.0. This fails when the server supports only TLS1.2 (as expected). Unexpected: why is it offering only TLS1.0?

2) If I set this AppContext switch (early in my add-in code): AppContext.SetSwitch (Switch.System.Net.DontEnableSchUseStrongCrypto, false); then as mentioned earlier in this thread, TLS1.2 gets offered on the handshake. But as also mentioned, this is a fixed list of protocols and won't adapt when the OS supports TLS1.3.

3) If I set the two AppContext switches: AppContext.SetSwitch (Switch.System.Net.DontEnableSchUseStrongCrypto, false); AppContext.SetSwitch (Switch.System.Net.DontEnableSystemDefaultTlsVersions, false); then: On Windows 10, I see TLS1.2 get offered. On Windows 7, I see TLS1.0 get offered. this seems consistent with this earlier reply.

My questions: Could someone (from MSFT?) confirm/explain the behavior I observe in 1) above (add-in targeted for 4.7 still offers TLS1.0 running on Win10)?

Is there any way to code my add-in in such a way that it will offer TLS1.3 when that protocol becomes available when running on Win7 and Win10 (and Win8.1)?

davidsh commented 5 years ago

The behavior you are seeing is expected (although not always intuitive):

Could someone (from MSFT?) confirm/explain the behavior I observe in 1) above (add-in targeted for 4.7 still offers TLS1.0 running on Win10)?

In terms of (1), while the Windows 7 or Windows 10 machine may have .NET Framework 4.7.2 installed, that doesn't alone control the default behavior. The default behavior is also controlled by what .NET Framework version is being targeted by the application. So, for example, you can have .NET 4.7.2 installed but the app is only being built (and targeting) a .NET Framework 4.6.2 SDK. And specifically, it is the application target and not necessarily the target of any library (DLL) that is built. In the case of a VSTO add-in for Excel, Excel is hosting the CLR/.NET Framework when it runs that add-in. I'm pretty sure that Excel itself is a native application and not managed. It sounds like Excel is targeting a .NET Framework version lower than 4.7.2 when it spins up the managed CLR environment to launch the add-in.

Your comments for (2) and (3) are consistent with expectations.

Is there any way to code my add-in in such a way that it will offer TLS1.3 when that protocol becomes available when running on Win7 and Win10 (and Win8.1)?

If you want to future-proof protocol selection, then you should always try to get "SystemDefaultTlsVersions" behavior activated. That means that the version of TLS protocol selected will be the highest one for the operating system. That means, right now, TLS 1.2. But in the future, Windows OS will add TLS 1.3 into the default mix of TLS protocols. And that means your application (or VSTO add-in) should benefit from that.

ShaunLoganOracle commented 5 years ago

Thanks @davidsh Your explanation of Excel's behavior makes sense.

re:

... TLS protocol selected will be the highest one for the operating system. That means, right now, TLS 1.2.

Except on Windows 7, where I see TLS 1.0 when I set both AppContext switches to false. If I have that wrong and there is some way to have Win 7 lead with TLS 1.2 without hardwiring the SecurityProtocol property, please let me know.

davidsh commented 5 years ago

Except on Windows 7, where I see TLS 1.0 when I set both AppContext switches to false. If I have that wrong and there is some way to have Win 7 lead with TLS 1.2 without hardwiring the SecurityProtocol property, please let me know.

While all of the Windows OS versions (7, 8.x, 10, etc.) support TLS 1.2, not all of them include TLS 1.2 in the "default set". Specifically Windows 7 does not include TLS 1.2 in the "default set". So, unfortunately, specifying "SystemDefaultTlsVersions" behavior does not help you get TLS 1.2 for Windows 7.

See: https://support.microsoft.com/en-us/help/3154519/support-for-tls-system-default-versions-included-in-the-net-framework

image

jozefizso commented 5 years ago

When you have the "SystemDefaultTlsVersions" activated, you end up with something better. Instead of providing a hard-coded default value for ServicePointManager.SecurityProtocol, you end up getting the SystemDefault setting. That allows the TLS protocol version to use the strongest OS default. Currently that is TLS 1.2. But in the future, new versions of Windows OS will change that to include TLS 1.3 etc.

This is not true!

A simple two line code will fail on fully patched Windows 7 SP1 with .NET Framework 4.7.2 application:

var c = new HttpClient()
await c.GetStringAsync("https://tls-v1-2.badssl.com:1012/");
davidsh commented 5 years ago

@jozefizso Unfortunately, Windows 7 is the exception here. See my comment above (https://github.com/dotnet/docs/issues/4675#issuecomment-498772703).

jozefizso commented 5 years ago

This is completely false for Windows 7:

...you should always try to get "SystemDefaultTlsVersions" behavior activated. That means that the version of TLS protocol selected will be the highest one for the operating system. That means, right now, TLS 1.2. But in the future, Windows OS will add TLS 1.3 into the default mix of TLS protocols.