Issue with Xamarin App Connecting to WCF Service over https - c#

I am developing an Xmarain.Forms app to initially work on Android along with a service it will be connecting to. The service is a WCF service and needs to use a secure transport to send messages so is set to use https.
I can correctly connect and use the service with both SoapUI and a console program built using the same client proxy library but when I try using the Xamarin App it fails. When run in the emulator the exception is a TimeoutException but when installed on an actual device the exception is WebException with message of "Error: SecureChannelFailure (The authentication or decryption has failed" with inner exception stack of:
IOException with message "The authentication or decryption has failed"
IOException with message "Error while sending TLS Alert (Fatal:InternalError)"
IOException with message "The authentication or decryption has failed.
IOException with message "Unable to read data from the transport connection: Connection reset by peer"
The full stack trace is included below as attachments. The full code is available at https://github.com/staircase27/WcfXamarinHttpBugExample along with the instructions of how to set it up and use it. The example code has connections using both http and https to show the difference and to show that one works and the other doesn't. I have also checked while testing that the devices can access the service using their web browsers so it's not a firewall or routing issue.
I have also wiresharked the connection to see where exactly the connection is failing and it's failing at the TLS v1.0 level. The app (on both devices I've tested) is sending a Client Hello and the service is responding with a TCP RST packet rather than a Server Hello. I have also performed a connection from the testing device using a web browser that succeeded and the main differences are in the types of encryption supported specifically the app only offers to use
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_MD5
TLS_RSA_WITH_DES_CBC_SHA
where as the working connections both used
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
A filtered wireshark with two connections is at https://github.com/staircase27/WcfXamarinHttpBugExample/raw/master/Mobile%20WCF%20https%20Capture%20-%20Filtered.pcapng. The first connection is from the app and fails with a tcp rst. The second is the start of the connection from the android web browser.
I have enabled all versions of TLS and all cypher suites but it hasn't changed the wireshark trace or exception in the app.
I have also checked the SChannel Event Logs as recommended by #tomasr and found the following event:
An SSL client handshake completed successfully. The negotiated cryptographic parameters are as follows. Protocol: TLS 1.0. CipherSuite: 0xc014. Exchange strength: 256
(Before enabling all version of TLS the events were:
An TLS 1.0 connection request was received from a remote client application, but none of the cipher suites supported by the client application are supported by the server. The SSL connection request has failed.
The following fatal alert was generated: 40. The internal error state is 1205.
)

Sadly as none of the suggestions in the comments worked I have had to work around this and am now using a RESTful WCF API and have implemented the client manually using HttpClient.

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

How to connect to remote gRPC service

I created a gRPC service and client in C# .NET Core 3.1. When I deploy the service to localhost, I can connect to it without a problem. But when I publish the service to a IIS via WebDeploy and start it there I cannot connect to it.
For a local deployment, the channel is initialized as follows:
var channel = GrpcChannel.ForAddress("https://localhost:5001");
For the remote deployment I change it to the following value, since it starts as a HTTP service on http://localhost:5000 on the remote machine (which I also failed to find out how to change - I would prefer it to start as a HTTPS service):
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var channel = GrpcChannel.ForAddress("http://1.2.3.4:5000");
1.2.3.4 is the IP of the remote machine, which I am able to ping. I also created a firewall rule to allow all inbound traffic on inbound port 5000.
The client application fails on the first remote call with the error message
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I fail to understand which measures I have to take to create a connection to the remote service. All example gRPC code I have found so far uses localhost as a deploy point and did not help me figure out the root cause of my problem.
Any help or pointers towards what I must have missed are appreciated.
From Tutorial: Create a gRPC client and server in ASP.NET Core, a warning almost at the end of the article, says
ASP.NET Core gRPC is not currently supported on Azure App Service or IIS. The HTTP/2 implementation of Http.Sys does not support HTTP response trailing headers which gRPC relies on...
Please refer to gRPC in production for ways to run your gRPC service in production.

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

Unable to connect IMAP server using StreamSocket when we are behind the Proxy

I'm writing a simple C# Store app to check email messages for IMAP. I'm using StreamSocket to connect IMAP server. But the problem is, when we are behind the proxy we are unable to connect to IMAP server and getting below error message.
"A connection attempt failed because the connected party did not
properly respond after a period of time, or established connection
failed because connected host has failed to respond. (Exception from
HRESULT: 0x8007274C)".
I have added the code snippet for the reference.
StreamSocket Socket = new StreamSocket();
await Socket.ConnectAsync(new HostName("imap.gmail.com"), "993", SocketProtectionLevel.SslAllowNullEncryption);
But the same code is working fine when there is no proxy.
Could you please help regarding this problem?
My Development Environment is C# using VS2013 with Windows 8.1 Operating System.
Thanks in advance.
The proxy you refer to is probably a web proxy only and all access to the outside is only allowed through this proxy. This means, that only web traffic (e.g. http, https and proxied ftp) can pass, but not other procols like IMAP, SMTP (mail sending) etc - because these cannot be tunneled through a HTTP proxy.

Http Request fails from ASP.NET code on Test server (also fails from IE... but not firefox!?)

I'm making HttpRequests to an external server from my ASP.NET application, to a URL like e.g.:
https://1.2.3.4:12345/Data/Users?Id=1
The server is running a service that responds to these requests with xml (like a web service). My code makes a GET request like this:
var wc = new System.Net.WebClient();
wc.Credentials = credentials; // username and password for service
// get data from server.
string s = Encoding.ASCII.GetString(wc.DownloadData(url));
return s;
It works fine on my Development machine.
But on my Test machine (old windows server 2003 64 box) it fails with this exception:
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.
---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
Googling tells me this is error has about a million different possible causes. None seem to apply.
Details:
I can make the request by pasting the URL into a browser, and this works on the Dev server, but on the Test server, it works on Firefox but not IE (!?!) IE gives a generic "Internet Explorer cannot display the webpage" - looks exactly the same if I change the IP address to something that doesn't exist.
The server is a secured by a self-signed SSL cert, which has been added to local computer's trusted certificate store on both clients (the test and dev boxes). But it's unlikely a certificate issue, since it works fine on dev, and still happens if you ignore certificate validation (on test).
I can telnet to the server (with the right IP and port) from the Test box.
Can anyone suggest something to try? A possible cause? A way to narrow it down a bit?
I finally found a relevant error in the server's windows event log:
An TLS 1.0 connection request was received from a remote client application, but none of the cipher suites supported by the client application are supported by the server. The SSL connection request has failed.
I created a new question, an actually answerable one, Here: How to add to the cipher suites available to ASP.NET HttpRequest client?

Categories

Resources