I am trying to create a simple xmpp client that connects to Gtalk.
The first part of the handshake seems to work.
Ror the TLS handshake I created a client SslStream, connected to the intended server (talk.google.com) and successfully got authenticated .
The first SSlStream.Read is to receive the greeting reply, it went fine . I do a SslStream.write to send my first command, but when i do my Sslstream.Read() to get the reply , i get this error."System.IO.IOException: Unable to read data from the transport connection: An established connection was aborted by the software in your host machine."
Can anyone point me to the right direction?
I am using code very similar to the example on msdn http://msdn.microsoft.com/en-us/library/system.net.security.sslstream.aspx
except that I switch from a Network stream to a Sslstream when TLS is negotiated.
netStream.Flush();
sslStream = new SslStream(netStream,
true,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
sslStream.AuthenticateAsClient("talk.google.com");
I'd try using one of the existing XMPP libraries for .Net:
Jabber-Net: http://code.google.com/p/jabber-net/
agsXMPP: http://www.ag-software.de/agsxmpp-sdk/
Even if you don't use of these libs, you'll get some good ideas from looking at the code.
In this case, you probably want:
sslStream.AuthenticateAsClient("gmail.com");
where gmail.com is the domain name from the JID you're trying to log in as.
Related
I have a C# .net server service application which listens on port 11111 for a connection. I have tested it with another c# test application which can send and recieve communication for and from the server.
Now the production scenario is that this C# .net server application is to recieve connection from, amongst others, a nodejs client which is encapsulated in Electron. So i create this function in NodeJS
const net = require( "net");
const socket = new net.Socket();
socket.connect('11111','127.0.0.1');
exports.socket = socket;
I import it in the IPC layer of Electron.
const { socket } = require("./socketInit.js");
and when doing that i get this error
A JavaScript error occurred in the browser process
Error: connect ECONNREFUSED 127.0.0.1:11111
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1146:16)
It wont connect to the server socket.
Im not even using the socket yet, but i understand that the connection attempt is doing the handshake and that must be where the error happens.
Does anyone have any idea what could be wrong ?
TY for your time!
Im quite sure it is because the code is in a renderpass which runs several times, and then the code in reality tries to open a connection on a port where a connection is already open each time there is a renderpass except from the first.
I destroyed the connection after sending and now i dont get the error anymore. But im not getting any data send to the server, but that is for another question.
I'm integrating this into an existing codebase, which i don't fully understand as im a total newb to NodeJS, Javascript and Electron, so im not sure how it all works :)
I have gRPC client / server code happily working on my local machine with the client using ChannelCredentials.Insecure but need to switch to a secure mode. I dont need any certificate checks just encrypted traffic.
Ive been unable to find any configuration of client server that talks to each other.
Running c# core server (gRPC 2.27.0), & c# .net framework client (gRPC 2.28.1).
The server says it publishing on http & https as below:
[20:12:58 DBG] Using development certificate: CN=localhost (Thumbprint: 3EDA2E5BD559D75C9DCF058E0A6994EED859CD34)
[20:12:58 INF] Now listening on: https://localhost:5001
[20:12:58 INF] Now listening on: http://localhost:5000
and client works with:
ChannelBase channel = new Channel("localhost:5000", ChannelCredentials.Insecure);
var client = new MyApp.MyAppClient(channel);
var response = client.Test(request)
If I switch client to SslCredentials as below
ChannelBase channel = new Channel("localhost:5001", new SslCredentials());
var client = new MyApp.MyAppClient(channel);
var response = client.Test(request)
I get the following errors.
server error
[19:32:53 DBG] Failed to authenticate HTTPS connection.
System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
client error
Grpc.Core.RpcException: 'Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")'
I've also tried adding (server) with no change in errors.
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =>
{
options.RevocationMode = X509RevocationMode.NoCheck;
options.ValidateCertificateUse = false;
options.AllowedCertificateTypes = CertificateTypes.SelfSigned;
});
Any suggestions as to what i need to do to make them talk.
So you need to specify roots.pem that correspond to the dev certificate you're using on your server when creating SslCredentials.
If you use parameterless SslCredentials(), it will use the default trust roots which only work for certificates that have been signed by publicly trusted certificate authorities (e.g. if you're talking "official" servers such as googleapis.com etc, definitely not the case for your development certificates that you are using on your server). So you need to use SslCredentials(yourCustomTrustRootsPem).
Btw, with SSL/TLS, there's no such thing as "no certificate checks". The client will ALWAYS check that it connected to the right server (server's certificate are verifiable by their trust roots) - without that the secure communication would make no sense because it would be too susceptible to man-in-the-middle attack. (the server checking authenticity of client is optional though).
Feel free to refer to https://github.com/jtattermusch/grpc-authentication-kubernetes-examples for extra resources.
I had a similar problem and finally found a solution to establish HTTPs connection between
.NET Framework 4.7.2 client (WPF app) and
ASP .NET Core 3.1 gRPC Server (Console).
Indeed the answer of Jan Tattermusch is correct. You need to supply the server side certificate as PEM to the constructor of SslCredentials and in addition, the certificate has to contain the DNS name or IP of the url you are contacting the server through. In your case, I suggest to manually create a self-signed certificate for each server instead of using the developer certificate. This one can be downloaded by your client and then be passed as SslCredentials. Works like a charm.
See my more details on how to do all the details in my answer to a similar question here:
https://stackoverflow.com/a/63565090/378415
Try to check on which port Grpc Service is running after deployment in any way either windows service or other , then give the same in client to consume the service. Eg: If your service is running on https://localhost:5000 then give the same in client.
It will work for sure.
Mostly you will get the above issue when you make a mistake of mismatching the address of service to client.
How can I use a Fiddler proxy with a TcpClient? The answer on this similar question did not work for me: How to use Proxy with TcpClient.ConnectAsync()?
var client = new Pop3Client();
var tcpClient = new TcpClient(hostname, port);
var sslStream = new SslStream(tcpClient.GetStream());
sslStream.AuthenticateAsClient(hostname);
client.Connect(sslStream);
After some discussion it turned out that the code to create a connection through a proxy which was referenced in the question actually worked, but
SSL decryption need to be off in Fiddler.
Otherwise Fiddler will not pass the original TLS handshake through but will create one between Fiddler and Server and another one between Client and Fiddler, where the last one has a certificate created by Fiddler. The client will usually not trust this certificate by default and thus fail the TLS handshake.
Moreover, Fiddler expects the traffic inside the TLS connection to be HTTP, i.e. the client sends a HTTP request and the server sends a HTTP response back. POP3 works differently by having both a different message syntax and by having the server start with sending and not the client.
It really has to be client.Connect(sslStream) as shown in the question and not something like client.Connect(tcpStream) as the OP had in its actual code. In the last case the client will just try to read the encrypted data from the connection and thus fail.
Building a small FTPS client (using TcpClient) to better understand how FTP works (mostly a learning experience).
So far I can connect on the control channel (port 21), issue AUTH TLS, grab the SslStream of the TcpClient connected on port 21, issue User/Pass commands and authenticate successfully over the SslStream.
Now, when I pass the FTP server PASV, I open a new TcpClient with that connection, no problem. My question(s) is(are) this(these): How do I get an SslStream for that new connection? Do I need to re-authenticate that SslStream?
Right now my code just hangs on AuthenticateAsClient:
var sslStream = new SslStream(_tcpDataClient.GetStream(), true, OnCertificateValidation, null);
try
{
sslStream.AuthenticateAsClient(_ftpServer, null, System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls, true);
The same code on my control TcpClient works fine:
var sslStream = new SslStream(_tcpControlClient.GetStream(), true, OnCertificateValidation, null);
try
{
sslStream.AuthenticateAsClient(_ftpServer, null, System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls, true);
Now, the control TcpClient runs right after an AUTH TLS command is sent to the server. I've tried sending AUTH TLS on the data channel with no luck.
Hoping someone can point me in the right direction. Thanks!
edit
A quick comment - if I use the straight GetStream from _tcpDataClient, I get a 250 response on the Control channel. This leads me to think my Data channel isn't encrypted? Is that correct?
I am trying inialise a tls tunnel with the .net SslStream but after opening the stream I always get the following error:
"Unable to read data from the transport connection: An established connection was aborted by the software in your host machine."
After I establish a tls connection and after sending a second message.
I've been searching for an answer for the last four days but there isn't any helpful information online!
edit:
I am trying to connect to talk.google.com
and I'm using the code sample from MSDN. Only difference is that I'm sending data before and when it is time to use tls i do the following:
public void SecureStream()
{
netStream.Flush();
sslStream = new SslStream(netStream, false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
sslStream.AuthenticateAsClient("talk.google.com");}
edit: I managed to eliminate the first error (small bug on how i was handling the send) now I always get
"Unable to read data from the transport connection: An established connection was aborted by the software in your host machine."
edit2: Im not sending any whitespaces I rewrote the message passing part and I still have the same problem.
I start with
String streamInit = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='google.com' version='1.0'>";
client.Send(streamInit);
Then on receive I have the following
static void client_MessageReceived(SyncronousClient source, string Result)
{
if (Regex.IsMatch(Result, "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"><required/></starttls>"))
{
String startTlS = "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
source.Send(startTlS);
}
else if (Regex.IsMatch(Result, "<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"))
{
//Do TLS Magic
source.SecureStream();
String streamReInit = "<stream:stream xmlns='jabber:client'xmlns:stream='http://etherx.jabber.org/streams'to='google.com'version='1.0'>";
source.Send(streamReInit);
}
else if (Regex.IsMatch(Result, "<mechanisms xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"))
{
//String AuthType = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='X-GOOGLE-TOKEN'/>";
String AuthType = "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\"/>";
source.Send(AuthType);
}}
It's unlikely to be your problem (unless .Net has started doing SNI under the covers), but when you call AuthenticateAsClient, pass in the same domain name that you used in your stream's to attribute (in this case, google.com). As well, you might need gmail.com instead of google.com:
sslStream.AuthenticateAsClient("gmail.com", null, SslProtocols.Tls, false);
As csharptest.net alluded to, make sure you don't have a keepalive timer that sends extra whitespace, or wait to start the timer until after TLS works. The only other way I can imagine your getting that error is if you don't have a ciphersuite that the server implements, but I know the .Net SslStream works against GTalk.
Lastly, use one of the existing .Net libraries for XMPP (there are 5 listed here), and you can start writing much more fun code right away. You're about to run into the inadequacies of the .Net XML system, and your regex-based approach won't work when you start getting partial stanzas or multiple stanzas in a single read.
That really doesn't make sense to me. The server, if using SSL, requires that the client perform the SSL handshake upon connection. Thus, I'm not sure what you mean by "I'm sending data before...". It sounds like your not immediately calling the AuthenticateAsClient. If this is the case, I suspect that is your problem. AFAIK, you cannot use the same socket/connection connection for both SSL and non-SSL communications. Either the server requires SSL, or it does not support it, it should never do both.
My previous answer above was in ignorance. Indeed it appears that the standard does in fact require that the connect send and receive data prior to the initialization of the SSL handshake. Really odd that they would do that... but whatever. After briefly reading through parts of the RFC it appears that you are expected to begin the SSL client auth immediately after the closing '>'. No trailing whitespace allowed which may be your problem?