WCF service (self-hosted) over HTTPS - Get negotiated SSL/TLS protocol version - c#

Due to security reasons, we wanted to disable TLS 1.0 support in our server on OS level (in followign SChannel registry):
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
But because the SQL Server service won't start with TLS 1.0 disabled, we had to leave the TLS 1.0 enabled on OS level.
What we are trying to do now is to force the usage of TLS 1.2 on application level rather than on OS level.
Our application is Client-Server, running on .NET 4.5.
On the Client, before calling the WCF service, we set:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
That ensures that the Client will send ClientHello message with TLS1.2 protocol.
But on the Server, which is self-hosted WCF service, we do not see how to force the TLS1.2 usage. The SSL/TSL negotiation on the Server side is based on the SChannel registry and thus setting the ServicePointManager.SecurityProtocol does not make any effect.
We would like to inspect the incoming WCF call in our Server code and check what TLS protocol used for the call, and close the connection if it is anything less than TLS1.2.
Is there any way how to get the incoming WCF call SSL/TLS protocol version? Something like HttpContext.WebSocketNegotiatedProtocol?

Have you tried using a custom binding with sslStreamSecurity?
<sslStreamSecurity requireClientCertificate="false" sslProtocols="Tls12" />

Related

I receive a CommunicationException on any port other than 443

I have a standard n-tier application (.Net 4.7.2) with a console server and a WinForms application both running on the same machine. The client and server communicate via WCF.
I get a CommunicationException on the client when I attempt to communicate with the server if I use any port other than 443 in my address binding. not specifying a port or explicitly specifying 443 works without an issue.
The error message is;
An error occurred while making the HTTP request to
https://localhost:44333/SecurityTokenService/issue/wstrust/mixed/anonymous.
This could be due to the fact that the server certificate is not
configured properly with HTTP.SYS in the HTTPS case. This could also
be caused by a mismatch of the security binding between the client and
the server.
here is my client binding for reference
<endpoint
address="https://localhost:44333/SecurityTokenService/issue/wstrust/mixed/anonymous"
binding="customBinding"
bindingConfiguration="MySecurityTokenEndpointBinding"
contract="System.ServiceModel.Security.IWSTrustChannelContract"
name="SecretTokenAuthenticationEndPoint" />
UPDATE: I have continued to investigate the issue myself and enabled WCF tracing. I can see from the trace logs the warning 'The Security Protocol cannot secure the outgoing message'
Make sure to use the correct way to call the wcf service, such as adding service reference, channel factory, etc. After reading your question, I think it is very likely as the error message says: 'This could also be caused by a mismatch of the security binding between the client and the server.'
You can use the following code to specify the TLS version:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13;
TLS1.3 is the latest TLS standard protocol, which is faster and has higher security.
Here is the reference: Transport Layer Security (TLS) best practices with the .NET Framework
The solution for me was to bind the SSL certificate to the IP Address and Port that my service was being exposed on. I used the following command from a command prompt;
netsh http add sslcert ipport={ipAddress}:{port} certhash={CertificateThumbprint} appid={appId}
Some points to note
If the above command fails; ensure you have the private key imported and not just the public certificate
I don't know if the appId is an arbitrary Guid; I used the Guid from my application shell project (a console application); It's the Guid that exposes your application to 'com'
Hopefully, this helps somebody in the future

The request was aborted could not create SSL/TLS secure channel - HttpWebRequest

I am making a webrequest to an 3rd party api and it was working fine. In between the certificate was changed for the API and now when i make the request from our dev environment, I am getting response as The request was aborted could not create SSL/TLS secure channel.
I tried setting different protocol in code and there is no change in the response. I was getting a different error in explorer also. But that was fixed after enabling SSL 3.
I am using httpwebrequest in the code. The initial dll was in .net 3.5 and it has been updated to .net 4.6 now.
When checking the certificate details in firefox, i can see the certificate is TLS 1.3. As far as i understand it is not supported in .net 4.6.1 as i get protocol not supported error when i set it TLS value.
The dev environment is a Windows server 2016. The same API is working in production in Microsoft cloud. Not sure about the exact server version.
Is there any way i can fix this issue.
Update
The certificate algorithm was not there in the cipher suites. Followed the below document to add the cipher suite and the issue is now resolved.
https://learn.microsoft.com/en-us/windows-server/security/tls/manage-tls
Unfortunately, you cannot fix this issue yet.
The .NET Framework simply delegates to the underlying Windows platform WinINet/SChannel APIs to make outgoing HTTPS calls, and WinINet/SChannel on Windows Server 2016 has not yet been rolled out with the necessary changes to allow TLS 1.3 outgoing connections.
Applications targeting Framework 4.7.1 and later will automatically use the highest TLS version available on the OS it's running on, and fall back to lower ones if the server you're connecting to doesn't support it, so you won't need the following code (unless your current code [or a dependency] already calls it with a lower version).
If you're stuck on Framework < 4.7.1, you can prepare your code for the eventual Windows updates:
// From .NET Framework 4.8.0, simply use SecurityProtocolType.Tls13
// (or rather don't use this code at all from 4.7.1, configure the TLS versions in the OS)
const SecurityProtocolType tls13 = (SecurityProtocolType)12288;
ServicePointManager.SecurityProtocol = tls13 | SecurityProtocolType.Tls12;
(Some sites may require you to also append | SecurityProtocolType.Tls11, but those sites really should update their servers).
This SecurityProtocolType value of 12288, meaning TLS 1.3, will now be future-proof and passed on to the underlying Windows API layer, but will now throw an exception if the site you're calling only speaks TLS 1.3:
Win32Exception: The client and server cannot communicate, because they do not possess a common algorithm
This fix therefore only works after TLS 1.3 support is rolled out to Windows Server.
Windows 10 and Windows Server 1903 have experimental support for this, but if you can't upgrade your .NET Framework from 4.6, I doubt you can install a Windows Server release that uses experimental features.
For more information, see the following references:
Microsoft TLS 1.3 Support Reference
Transport Layer Security (TLS) best practices with the .NET Framework
TLS1.3 is it supported?
Protocols in TLS/SSL (Schannel SSP)
The certificate algorithm was not there in the cipher suites. Followed the below document to add the cipher suite and the issue is now resolved.
https://learn.microsoft.com/en-us/windows-server/security/tls/manage-tls
The same error can be seen when web applications don’t have permissions to access certificates.
Our web application uses client certificates to authenticate against remote web services. When the certificate was reissued and installed we started to see this error.
The solution was to grant permissions to the account that the web application runs as.
On Windows:
Manage computer certificates > Certificates – Local Computer >
Personal > Certificates
Right-click the certificate > All Tasks >
Manage Private Keys
Then Add the relevant account for the app pool – in our case it was Network Services
Hope this helps someone

WCF Service + Client (TLS1.2 Issue)

Our Server has had SSLv3, TLS1.0 and TLS1.1 disabled. Due to this, Visual Studio fails when trying to Add Service Reference when trying to retrieve the WSDL.
"The underlying connection was closed: An unexpected error occurred on a send.
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
An existing connection was forcibly closed by the remote host
Metadata contains a reference that cannot be resolved:
An error occurred while making the HTTP request to https://mywebsite.com/Service/Service.svc?wsdl. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.
The underlying connection was closed: An unexpected error occurred on a send.
Authentication failed because the remote party has closed the transport stream.
If the service is defined in the current solution, try building the solution and adding the service reference again."
The WSDL is accessible in the browser. The WSDL downloads okay when TLS 1.0/1.1 and SSLv3 are enabled. However, due to PCI requirements we have to disable SSLV3, TLS1.0 and TLS1.1.
I am aware of the following System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; but am not quite sure if this would go in the connecting Console Client or the WCF Service (or both).
Any advice would be appreciated
The line below line needs to be in the client, as that is what is making the connection.
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
As per this blog TLS 1.2 and .NET Support: How to Avoid Connection Errors, the above will work for .Net 4.5
For .Net 4.6 and above it will default to TLS 1.2 and you do not need to specify TLS 1.2
For .Net 4.0 you need the below instead.
System.Net.ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
NET 3.5 or below you need to install the appropriate Microsoft Patch for your OS (listed in the blog).

Packets not being captured when negotiating TLS versions with .NET SslStream

My set up is:
I have a server listener app that only accepts TLS 1.0 connections.
I have a client app that uses SslStream.AuthenticateAsClient to configure a secure connection
I am using WireShark to monitor traffic between client and server
On the client machine I use the SecurityProviders\SCHANNEL\Protocols registry keys to manipulate which version of TLS I want to use. If I force the client to use TLS 1.2 I get the expected error of "The client and server cannot communicate, because they do not possess a common algorithm". However, the only packets that get captured in WireShark are the TCP 3-way handshake.
Conversely, if I explicitly specify Tls1.2 in the call to SslStream.AuthenticateAsClient I see the Client Hello and Server Hello TLS messages in WireShark. And of course, I see the same expected error message as above.
My question is, when I'm only using the Registry to manipulate TLS versions how come I do not see any TLS packets being sent through WireShark? How does Windows/.NET know that the remote server does not support TLS 1.2?
Thanks

SSL Handshake fails from asp.net application - works in browser

I am trying to do a simple get request using the System.Net.Http.HttpClient (using GetStringAsync). The request fails when done from my webapi asp.net application, but it works correctly from the browser and postman.
The request fails with Authentication failed because the remote party has closed the transport stream.
Note: It works correctly when doing get request to other servers using TLS.
I used the following to confirm that the issue was with ssl. Using these two lines makes the request work, but obviously disabling certificate validation is not a real solution.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
I tested the server using https://www.ssllabs.com and it seems that
everything is working correctly on there. It supports TLS 1.1 and 1.2.
To find out what is going on I was looking at the packages in wireshark, but since I don't know much about ssl, I am not learning much. Looking at the packages from the browser request I can see that it is using the TLS 1.2 protocol and that the handshake looks correct.
The following picture shows the client initiating two separate ssl "ClientHello's". For some reason the server doesn't respond with a SSL handshake response.
Hope someone can help me figure out what is going on.
I tested the server using https://www.ssllabs.com and it seems that everything is working correctly on there. It supports TLS 1.1 and 1.2.
Your client is doing a TLS 1.0 handshake only. If the server supports only TLS 1.1 and TLS 1.2 but not TLS 1.0 the connection will fail. Since modern browsers all support TLS 1.2 browsers will work.

Categories

Resources