Docs: Transport Layer Security (TLS) best practices with the .NET Framework

Created on 15 Mar 2018  路  94Comments  路  Source: dotnet/docs

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

Pri3 discussion doc-enhancement

Most helpful comment

.NET Framework does not support TLS 1.3 yet. It is something we will start working on soon (cc @wfurt). The bottom line is that to use TLS 1.3, we have to use new Windows API, therefore we have to change our code in .NET Framework and the change is rather large due to other requirements of TLS 1.3 (things that don't matter in TLS 1.2 and lower).

Also note that Windows 10 with TLS 1.3 (non-experimental support) was released only recently, I think that only in Windows 10 Insider builds (@wfurt has more details).

In .NET Core we implemented TLS 1.3 support just recently in upcoming RC1 build of .NET 5. You can try it out there (on OS build that supports it too of course).

All 94 comments

@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.

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.

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

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?

@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

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.

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

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.

@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.

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.

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?

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.

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?

@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?




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

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?

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?

@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

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?

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

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.

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.

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)

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?

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.

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"

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?

@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

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.

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.

@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?

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.

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!!

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?

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.

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

@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.

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.

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

@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.

@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 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?

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)?

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.

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.

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

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/");

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

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.

@davidsh well, that does not help us writing secure applications. We are now forced to always set the TLS 1.2 in .NET application and it forbids us from using any better protocol.

Although Win 7 SP1 falls out of extended support in 5 months @davidsh Is there anything you can update in the docs to help clarify this? https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls#if-your-app-targets-net-framework-47-or-later-versions

.NET 4.7.1 was release in October 2017! We hit this bug in production almost two years ago! Making it an issue with OS which will not be supported in 5 months is silly.

..If I understand everything correctly..

@jozefizso I don't think the fault is with .NET Framework. In the whats new for 4.7 it says

image

Meaning that the option to use the default OS protocol instead of hardcoding it as you used to have to do. If you configure .NET to use the OS default, it uses the OS default. However, the limitation at hand is that Windows 7 does not include TLS 1.2 as a default protocol. There is no bug from the .NET Framework standpoint.

Consider how how Windows 7 mainstream supported ended in 2015 and extended support ends in a few months. TLS 1.2 was added to Windows 7, the default behavior of the OS was not changed. As newer security protocols get released, .NET Framework will still default to the OS when you specify, but the OS needs to be updated to use the new protocol and also needs it to have it set as the default. I can't say if Windows 7 will or wont be updated before extended support ends, or even after.

This totally contradicts the Developers need no longer hard-code a TLS version - we must hard code it for our apps to work on Windows.

This also contradicts the KB3140245 which changes default protocol to TLS 1.2 - even with this patch installed, .NET app will not connect to TLS 1.1/1.2 website.

Another statement which is false, from https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls

To ensure .NET Framework applications remain secure, the TLS version should not be hardcoded. .NET Framework applications should use the TLS version the operating system (OS) supports.

It will not use what OS supports - it will use insecure default!!!

@jozefizso If you add these registry settings to your Windows 7 install, TLS 1.2 works by default. I just created an Azure VM with Windows 7, installed Visual Studio, created a sample app, validated it didn't work, set these registry keys, validated it did work.

Here is a .reg file that sets the key

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client]
"DisabledByDefault"=dword:00000000
"Enabled"=dword:00000001

I don't think it is acceptable to modify registry this way on customers' devices.

The documentation is clear: .NET Framework applications should use the TLS version the operating system (OS) supports

Windows 7 SP1 supports TLS v1.2 therefore this is a bug in the .NET Framework. This issue did not exist in .NET Framework up to v4.7.1

Let's say the server support TLS 1.0, 1.1 and 1.2 connections.

.NET applications targeting up to 4.6 will correctly connect using TLS 1.2 on Windows 7 SP1.

Retarget the application to .NET 4.7.1 and you have suddenly security hole in your application as it will connect with TLS 1.0!!! This is security issue!

@david1995 so what happens if we install support for TLS 1.3 on Windows 7/8/10?

The default protocol is TLS 1.0, 1.2, 1.2 respectively and supported will be 1.3, 1.3, 1.3. Yet with this behavior, .NET will choose TLS 1.0, 1.2, 1.2 - it will not choose the highest supported and most secure protocol.

Are there any potential TLS 1.2 issues with ws2007HttpBinding (.NET 4.5, .NET 4.7.2)?

<ws2007HttpBinding>
        <!-- This binding is used for token issuer endpoints that require username token over SSL -->
        <binding name="UserNameTokenIssuerBinding">
          <security mode="TransportWithMessageCredential">
            <!--
            Load Balancing with the WSHttp Binding and the WSDualHttp Binding
            http://msdn.microsoft.com/en-us/library/ms730128.aspx
            -->
            <message establishSecurityContext="false" clientCredentialType="UserName" />
            <transport clientCredentialType="None" />
          </security>
        </binding>
      </ws2007HttpBinding>

Are there any potential TLS 1.2 issues with ws2007HttpBinding (.NET 4.5, .NET 4.7.2)?

@mconnew Can you help answer this question?

@osudude, the only issue with TLS1.2 which is not unique to WCF is if either the client or server certificate (in your case, no client cert but I'm providing the general answer) is using the certificate hash algorithm md5, the certificate can't be used with TLS1.2. So if you have an existing service with a certificate using the md5 hash algorithm and you configure both ends to support TLS1.2, they will negotiate TLS1.2 and then fail the rest of the TLS handshake as the certificate can't be used. As I said, this is a general problem and not specific to WCF.

@mconnew : Don't use MD5 certs. They've been broken. By this point, those must be self-signed certs. Upgrade your certs.

@jhudsoncedaron, at no point did I suggest or advocate using MD5 certs. I answered the question accurately.

@ShaunLoganOracle , @jozefizso , @davidsh I have only now hit this problem with Windows 7 and I solved it simply by adding the following AppContext switch in the .exe.config file and placing it alongside the application:

<?xml version="1.0"?>
<configuration>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Net.DontEnableSystemDefaultTlsVersions=true"/>
  </runtime>
</configuration>

Note that this is _the opposite_ of @ShaunLoganOracle proposal, where the same switch was used but set to false. Unfortunately, the switch name is a negative clause (why would you ever label a boolean property in the negative is beyond me). This means setting it to false effectively says that you want .NET to use SystemDefaults which has no effect. Turning it true however makes the runtime use the .NET framework's own defaults, which for .NET 4.7.2 includes Tls12 (the same as .NET 4.6) and I can confirm it works seamlessly on a clean installed and patched Windows 7 SP1.

This is also confirmed by the AppContextSwitchOverrides doc pages, which states this switch was introduced with .NET 4.7, and it's function:

Disables SystemDefault TLS versions reverting back to a default of Tls12, Tls11, Tls.

@jozefizso I agree with you of course that system defaults are always preferred in general, so applications should not hard-code the TLS version. However, Windows 7 is officially end-of-life, so it is reasonable to expect that the TLS protocol will never be upgraded there. Since the .exe.config file can simply be deployed side-by-side with the application using an installer, you could make an easy script to decide to deploy this for your application on Win7 _only_ and I believe this is a totally reasonable choice, MUCH better than forcing registry keys or doing nothing (which simply breaks).

@davish This may not be relevant anymore given that Microsoft has EOL Win7, but it would have been nice to explicitly discuss the exceptional situation of Windows 7 in the docs and present this recommended workaround for legacy maintainers. I believe it would have saved a lot of people several headaches: it is easy to deploy, with zero future maintenance implications, and much less confusing than fiddling with the registry.

Hello,

First, thank you very much for the useful documentation for the tls migration. Also, some of our dependencies have moved to tls12.
But I noticed there are some inconsistent behavior in Azure Cloud Service than the behavior described in document.

We moved our code base to target .net framekwork 4.7.2, which based on the document that it will default SecurityProtocol to SystemDefault and will be negotiating tls12 as defualt.
However, when I debug run the Azure Worker Role (Cloud Service) local with Azure Compute Emulator I noticed the SecurityProtocol is still stuck on tls | ssl3 ....
I tried several ways (Such as specifying context override in app.config, changing registries...etc) with no luck :( and ended up having to put.

ServicePointManager.SecurityProtocol = SecurityProtocolType.tls12;

in order to make it negotiate tls12...
Wouldn't .net framework 4.7.2 do not require us to put this hard coded line in the code ??

System Info:
Test machine: Windows 10
Target framework: 4.7.2
Worker Role .cscfg osFamily: "6"

Thanks in advance

Wouldn't .net framework 4.7.2 do not require us to put this hard coded line in the code ??

That would be the most sensible implementation - so we don't have to hard code security settings into code.

In reality this implementation is so broken, it cannot use the correct (the most secure) TLS from the OS.

Hi @jozefizso
So do you mean that even though the document web page asks us to remove all codes specifying security protocol, we should still specify it in our code ?

Thanks

@cwang25 : Known issue. The document isn't wrong. The .NET Framework code is wrong.

Hi @jhudsoncedaron

so do you mean we still need to specify in code then ?
Is there a ETA for the fix ?

@cwang25 : MS is in internal debates on fixing it because the .NET team wants a higher minimum TLS version than the Windows team ships. But once touch that setting at all, eventually the setting is too low and has to be fixed in application code. :(

@jhudsoncedaron
I see. Thank you so much for the information.
So is this issue occurs across all .net framework ? or just specifically 4.7.2 ?
(or the hard coded tsl12 is needed across all .net framework versions now ?)

@cwang25 : MS is in internal debates on fixing it because the .NET team wants a higher minimum TLS version than the Windows team ships. But once touch that setting at all, eventually the setting is too low and has to be fixed in application code. :(

Can you please clarify what "internal debates" you're talking about? I'm a member of the .NET team and am not aware of what you are talking about.

@davidsh: When I filed https://github.com/dotnet/aspnetcore/issues/14997 I learned of it.

Hi @jhudsoncedaron @davidsh ,

I ready through the threads from above, looks like the issues only occurs when OS is Windows 7 ?
For my case it's Windows 10, so my case might be some different issue?

Thanks

Adding Tls3 paints us into the same hole again when Tls4 comes along. And we keep telling people not to do this, to let the OS decide, but then we do it ourselves.

@jhudsoncedaron The best comment from that thread! Thanks for sharing this issue.

@cwang25 As far as I understand, there should only be problems on Windows 7, which you can fix with an explicit app.config file deployed next to the executable on install. Have you experienced otherwise on your Azure deployments?

@cwang25 how do you debug the Azure Worker Role? VS has test runner which targets .NET 4.5.2 which flips defaults of your app under debugger (see https://github.com/microsoft/dotnet/issues/1138#issuecomment-589852105).
The easiest way to try is to print SecurityProtocol to output/log in release without debugger attached and confirm - here's sample code: https://github.com/microsoft/dotnet/issues/1138#issuecomment-589779845

Hi @karelz
Thank you very much for the information.

I'm using Visual Studio 2019 and targeted framek work is .net 4.7.2

The way I debug Azure worker role, I simply right click on the worker role and click 'Debug' then let VS to trigger Azure Emulator to start up.

Runner where I can check the runner ? (So far I only find the place to change the target framework and osFamily setting in .cscfg file..

thanks!

Inspect the processes debugging runs, check the config files. That is likely the safest way.
Also check that the problem is debug only and not in release/production.

Hello,

Thanks for the great document! It's really helpful for us when moving our project to target for .NET Framework 4.7.2. The ASP .Net and WPF applications are all working well with TLS 1.2.

But one little issue with the installation package. We are using wix project to package our product, and it calls some CustomAction written in C#. The CustomAction works fine (using TLS 1.2 by default) when called from a testing .Net application. However, it doesn't work (not using TLS 1.2) when called from the msi file.

We have added and to the wixproj file as below, but seems doesn't work.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <TargetFramework>net472</TargetFramework>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>

Appreciated for any suggestions. Thanks!

Hello,

Thanks for the great document! It's really helpful for us when moving our project to target for .NET Framework 4.7.2. The ASP .Net and WPF applications are all working well with TLS 1.2.

But one little issue with the installation package. We are using wix project to package our product, and it calls some CustomAction written in C#. The CustomAction works fine (using TLS 1.2 by default) when called from a testing .Net application. However, it doesn't work (not using TLS 1.2) when called from the msi file.

We have added and to the wixproj file as below, but seems doesn't work.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <TargetFramework>net472</TargetFramework>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>

Appreciated for any suggestions. Thanks!

Just realized that the custom action project contains a CustomAction.config, Tried to put the following section there and wix complained that 'If you are binding to .NET 4 or greater add useLegacyV2RuntimeActivationPolicy=true to the element.'

    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>

After adding useLegacyV2RuntimeActivationPolicy=true, seems it doesn't honor the 4.7.2 settings then. Probably something restriction with wix project. Haven't found workaround yet.

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.

Hi ,
Can you elaborate on below thing.
"For the HTTP transport with a WCF client, we have the behavior that the OS components IIS or HTTP.SYS are configured to use."

@davidsh , all-
Following up on my previous post: I am now following the guidelines to "get "SystemDefaultTlsVersions" behavior activated" and I can't seem to see the TLS 1.3 support I expect.
My env: an Excel VSTO C# add-in, Windows 10 1909, .NET 4.8
Code has:

AppContext.SetSwitch ("Switch.System.Net.DontEnableSystemDefaultTlsVersions", false); // very early in add-in code
// then, leave ServicePointManager.SecurityProtocol alone

What I see is that my client code offers TLS 1.2 (from a verbose log):

System.Net.Sockets  [8724] Data from Socket#14347911::Send
System.Net.Sockets  [8724] 00000000 : 16 03 03 00 A5 01 00 00-A1 03 03 5F 3F DE 83 1D : ..........._?...

The 16 signifies "handshake"; the 03 03 is TLS1.2. Fine.
However, with this combination of OS + .NET, my understanding is that TLS1.3 should be available (experimentally). I cannot find a way to get my client to offer TLS1.3. I have tried:
1) Checking the checkbox for "Use TLS 1.3 (experimental)" in Internet Options > Advanced
a. By itself this checkbox does not change the behavior - client leads with TLS 1.2
2) Adding two registry values:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client]
    "DisabledByDefault"=dword:00000000
    "Enabled"=dword:00000001

With the registry values added - I see the client lead with TLS1.0 (16 03 01 ...). This happens when the checkbox for "Use TLS1.3" is checked or unchecked.

How can I test that my client will offer TLS 1.3 when I use the system default behavior?

@ShaunLoganOracle : Last I checked TLS 1.3 doesn't work on Windows at all yet. It surprised me when I forced TLS 1.3 only on both client and server and it just failed outright.

.NET Framework does not support TLS 1.3 yet. It is something we will start working on soon (cc @wfurt). The bottom line is that to use TLS 1.3, we have to use new Windows API, therefore we have to change our code in .NET Framework and the change is rather large due to other requirements of TLS 1.3 (things that don't matter in TLS 1.2 and lower).

Also note that Windows 10 with TLS 1.3 (non-experimental support) was released only recently, I think that only in Windows 10 Insider builds (@wfurt has more details).

In .NET Core we implemented TLS 1.3 support just recently in upcoming RC1 build of .NET 5. You can try it out there (on OS build that supports it too of course).

@karelz Thanks for clarifying! That helps me (and I hope others) understand. Since my add-in is targeting the .NET Framework and not .NET Core, it sounds like we'll need to wait for an update to .NET Framework to be able to test (and take advantage of) the ability for the System Default protocols behavior to automatically offer TLS 1.3. And, as you point out, the underlying version of Windows 10 must have the support too.

yes, that is correct. The setting via registry will stop working when using old crypto API. The main reason was compatibility problems. TLS 1.3 has significant flow changes and many old apps (including .NET) could not handle it out of the box. When ready, I recommend to test on Windows insider builds. They should generally be good with exception of https://github.com/dotnet/runtime/issues/40679. 1909 is definitely too old.

Yet another question. With the set up mostly* as in this post, I used Control Panel > Internet Options > Advanced, and then unchecked the "Use TLS 1.2" item in the Security category (leaving "Use TLS1.1" checked). When I run my test case with verbose logging, I can see that .NET is offering 16 03 03 (TLS 1.2) in the handshake. I expected that with the use System Default behavior in force, TLS 1.1 would be offered. Could someone clear up my misunderstanding?
*in this latest test, it used the Excel add-in on Windows 10 1809, .NET 4.7

@ShaunLoganOracle that setting seems to be just for the integrated internet browser (home page is a huge hint IMO), not for everything in the OS. AFAIK you have to set up registry for Schannel component to change TLS versions enabled/disabled defaults.

Thanks @karelz !
For any others that encounter this thread, I disabled TLS 1.2 (for Client) using the registry setting from this page. Ran my test and I can see that TLS 1.1 is offered in the handshake: 16 03 02

Just wanted to understand whether there is any limitation of the CIPHER Suites in the TLS 1.2 that is supported by Azure Cloud Services ? The article mentions that it doesn't support weak/older ciphers. Is there any list as such for the list of Ciphers that are supported by the azure services ?

Hi,

From the document:

Do not specify the TLS version. Configure your code to let the OS decide on the TLS version.

By default the OS enables TLS version 1.0 and 1.1 which are currently under deprecation.
Is there any way to enforce an minimal TLS version at application level to be sure that only TLS version 1.2 or more is offered by the a client application?

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

Is there a plan that this registry settings are applied by default (what I mean is TLS 1.0 and TLS 1.1 disabled by default).

@pierre-loup-tristant-sonarsource : No. I tried to write that code. Half a day in I realized it's never going to work. For such an API to exist, MS has to provide it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LJ9999 picture LJ9999  路  3Comments

tswett picture tswett  路  3Comments

LJ9999 picture LJ9999  路  3Comments

gmatv picture gmatv  路  3Comments

stanuku picture stanuku  路  3Comments