SslStream and SSL protocol not recognized (i think)
i wrote this simple apps to connect to an IRC server but it doesn't work :(
| |
using System;using System.Collections.Generic;using System.Text;using System.Net;using System.IO;using System.Net.Security;using System.Net.Sockets;using System.Security.Cryptography.X509Certificates;namespace provaSSL{ classProgram{ staticvoid Main(string[] args){ try{ string certName ="";TcpClient sslClient =newTcpClient();sslClient.Connect( "irc.discostars.de", 7000);SslStream sslStream =newSslStream(sslClient.GetStream(),false, CertificateValidationCallback);sslStream.AuthenticateAsClient (certName, null, System.Security.Authentication.SslProtocols.Ssl2 |System.Security.Authentication. SslProtocols.Ssl3,false);StreamReader sslReader =newStreamReader (sslStream);byte[] buffer =newbyte[20];Console.WriteLine (sslReader.ReadLine ());} catch (System.Exception ex){ Console.WriteLine(ex.Message);} } staticbool CertificateValidationCallback(object sender,X509Certificate certificate,X509Chain chain,SslPolicyErrors sslPolicyErrors){ returntrue;} } }
|
Received an unexpected EOF or 0 bytes from the transport stream.
Press any key to continue . . .
i receive this error. Can someone help me?
[5344 byte] By [
luca82] at [2008-2-4]
just to be more precise:
with mIRC + OpenSSL I am able to connect to that server and with the same code i am able to connect to other servers which require SSL.
So i think the SSL required by that server is not implemented in SslStream.
Anyone can help me? Thanks in advance
Hi Lucas,
If this is Whidbey 2.0, then did you try System.Security.Authentication.
SslProtocols.TlsMahesh
yeah, i tried this
| | sslStream.AuthenticateAsClient (certName, null, System.Security.Authentication.SslProtocols.Ssl2 | System.Security.Authentication. SslProtocols.Ssl3 | System.Security.Authentication. SslProtocols.Tls, false); |
but it doesn't connect :(
Anyone can help?
plz. help me, i have provided the whole code... anyone can tell me what's wrong?
Luca82,
SslStream.AuthenticateAsClient should work irrespective of the remote SSL server implementation. It infact uses the same SSPI API's that HttpWebRequest uses to establish SSL handshakes. Having said that, It looks like that we are not completing the Server certiifacte handshake. I will try it with the latest RTM bits internally and let you know of the status tomorrow.
enabling tracing using config should help you to diagnoise better.. Make this xml file as <yourexename>.exe.config.. It will log into the file specified in the config... here it is System.Net.trace.log in the same dir as the exe.
<?xml version="1.0" encoding="UTF-8" ?> <configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.Net">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
<source name="System.Net.Sockets">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
<source name="System.Net.Cache">
<listeners>
<add name="System.Net"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add
name="System.Net"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="System.Net.trace.log"
/>
</sharedListeners>
<switches>
<add name="System.Net" value="Verbose" />
<add name="System.Net.Sockets" value="Verbose" />
<add name="System.Net.Cache" value="Verbose" />
</switches>
</system.diagnostics>
</configuration>
enabling logging i get this, but i'm not able to understand the data read by the Receive function:
| |
System.Net.Sockets Information: 0 : TcpClient#33574638::TcpClient(InterNetwork#2) System.Net.Sockets Information: 0 : Socket#33736294::Socket(InterNetwork#2) System.Net.Sockets Information: 0 : Exiting Socket#33736294::Socket() System.Net.Sockets Information: 0 : Exiting TcpClient#33574638::TcpClient() System.Net.Sockets Information: 0 : TcpClient#33574638::TcpClient() System.Net.Sockets Information: 0 : Exiting TcpClient#33574638::TcpClient() System.Net.Sockets Information: 0 : TcpClient#33574638::Connect(irc.discostars.de) System.Net.Sockets Information: 0 : DNS::GetHostEntry(irc.discostars.de) System.Net.Sockets Information: 0 : DNS::GetHostByName(irc.discostars.de) System.Net.Sockets Information: 0 : Exiting DNS::GetHostByName() -> IPHostEntry#35191196 System.Net.Sockets Information: 0 : Exiting DNS::GetHostEntry() -> IPHostEntry#35191196 System.Net.Sockets Information: 0 : TcpClient#33574638::Connect(252:7000#-52062067) System.Net.Sockets Information: 0 : Socket#33736294::Connect(252:7000#-52062067) System.Net.Sockets Information: 0 : Exiting Socket#33736294::Connect() System.Net.Sockets Information: 0 : Exiting TcpClient#33574638::Connect() System.Net.Sockets Information: 0 : Exiting TcpClient#33574638::Connect() System.Net.Sockets Information: 0 : TcpClient#33574638::GetStream() System.Net.Sockets Information: 0 : Exiting TcpClient#33574638::GetStream() -> NetworkStream#48285313 System.Net.Sockets Information: 0 : Socket#33736294::Send() System.Net.Sockets Verbose: 0 : 00000000 : 80 4C 01 03 01 00 33 00-00 00 10 00 00 04 00 00 : .L....3......... System.Net.Sockets Verbose: 0 : 00000010 : 05 00 00 0A 01 00 80 07-00 C0 03 00 80 00 00 09 : ................ System.Net.Sockets Verbose: 0 : 00000020 : 06 00 40 00 00 64 00 00-62 00 00 03 00 00 06 02 : ..@..d..b....... System.Net.Sockets Verbose: 0 : 00000030 : 00 80 04 00 80 00 00 13-00 00 12 00 00 63 43 50 : .............cCP System.Net.Sockets Verbose: 0 : 00000040 : F2 C9 47 AD 2D AC 8D 14-94 0C 78 7F 96 22 : ..G.-.....x.." System.Net.Sockets Information: 0 : Exiting Socket#33736294::Send() -> 78#78 System.Net.Sockets Information: 0 : Socket#33736294::Receive() System.Net.Sockets Verbose: 0 : 00000000 : 15 03 01 00 02 : ..... System.Net.Sockets Information: 0 : Exiting Socket#33736294::Receive() -> 5#5 System.Net.Sockets Information: 0 : Socket#33736294::Receive() System.Net.Sockets Verbose: 0 : 00000005 : 02 28 : .( System.Net.Sockets Information: 0 : Exiting Socket#33736294::Receive() -> 2#2 System.Net.Sockets Information: 0 : Socket#33736294::Receive() System.Net.Sockets Verbose: 0 : 00000007 : : System.Net.Sockets Information: 0 : Exiting Socket#33736294::Receive() -> 0#0 |
A few questions.
Is AuthenticateAsClient succeeding? It seems like it is.
Otherwise it would not come to the point of reading the stream.
Can you please put a console.WriteLine("succeeded...") after the AuthenticateAsClient()?
Now if it suceeds you can get the remote certificate and examine the certificate to make sure that you got SSL
I suspect the
StreamReader = .... code
and the associated ReadLine().
I would read directly from the stream and make sure that you are getting the data.
Then make sure that the stream is indeed a text stream and not a binary stream that males ReadLine() to throw an exception...
but the same code works with other ssl irc servers. The only one it doesn't work is this one. So I think is something with SslStream.
Plus, I am using StreamReader so i don't have to worry about every "\r\n" i receive from the irc server.
And i simply do a return true in my authenticate callback, cause i don't care about the certificate, i simply want to login :)
However i'll try reading directly from the stream.... I don't need to use that streamreader but how can i workaround it?
In my actual code i do this.... what do you suggest?
| |
public string ReadLine () { string buffer = ""; byte[] s = new byte[1]; int count = 0; try { while ((s[0] != '\n') && (buffer.Length <= 3000) && (count < 10000)) { if (ircSServer.Receive (s) > 0) buffer += Encoding.ASCII.GetString (s); count ++; } if (buffer.Length > 3000) buffer = ""; } catch (SocketException se) { if (se.ErrorCode != 10060) { errorString = "ReadLine: SocketException: " + se.Message; errorCode = se.ErrorCode; buffer = null; } buffer = ""; } catch (SecurityException se) { errorString = "ReadLine: SecurityException: " + se.Message; buffer = null; } catch (Exception e) { errorString = "ReadLine: Exception: " + e.Message; } finally { Thread .Sleep (50); } return buffer; }
|
I'm goign to explain it a bit so you can undestand my choices, and suggest me some good programming :)
Since i had some problems with streamreader (i don't remember which... it's a long time i wrote this "base code") i decided to handle myself the "\r\n"
for being sure i don't miss them i read one char at a time from the stream, till i read "\n"
I use some other "tricks" to read a line.... i use buffer.length cause i don't wan some sort of buffer owerflow attack.... cause if i countnue to read undefenitely i could eat all the memory (nearly impossible cause this is checked by the irc server :)) and i use a count variable just to be sure that i don't read in a loop....
that's why i noted that sometimes the Receive doesn't throw an exception, but returns an empty string so if i continue to read from the stream i would finsh in a loop.
another thing i noted is that if i don't set a timeout for reading/writing from stream, and since i don't use asynchronous functions, sometimes reading/writing hangs... so i catch SocketException but ignore the 10060 errorcode, cause it simply tell me that the timeout expired, but no "real" error occurred.
i also included the while loop in a try cacth statement so i can catch the network errors. is this right? does it slow down the whole loop? is there any other way?
I would really appreciate to ear your anwers, cause i hope to learn a lot from you guys :)
plz tell me everything you think is wrong or can be made in a different way.
Thank you very much for your help
P.S. I wrote this code using a free class from www.mentalis.org for the ssl socket, but the principles are the same for any socket class will use
P.P.S. don't forget to help me with the SslStream :)
First I don't think this is an SSL Stream issue. Once the Server/Client is authenticated using certificates, there not much left except to encrypt data going back and forth.
In your case, the SSL Authentication seems to be working fine - Correct?
If not, please let me know.
Once the SSL Auth is done, the sever and client can exchange any data.
What I am saying is that I am not sure whether the server is sending \r\n or not.
I don't even know what to expect from the server. I also don't know what encoding the server is using. When you created the StreamReader, it could be using default encoding to conver bytes to strings. Are you sure that is the right thing to do for your app?
I would say that first dump the bytes using stream, look at what the server is sending and decide what encoding to use and then use the stream reader.
Writing one yourself is a waste of your time, and you should ideally use the one that comes with the framework
But can use a stream reader only when you know that the format the server is
sending is infact "TEXT" and you know the exact ENCODING to use
Are you downloading xml? If thats the case you should not use a stream reader at all.
On reading the thread one more time, it looks like your authenticate as client
is failing. could you confirm?
once again i think is a SslStream issue because of what said mahalavar in a previous post:
" It looks like that we are not completing the Server certiifacte handshake. I will try it with the latest RTM bits internally and let you know of the status tomorrow.
"
However.. yes, the auth fails cause i suspect the sslstream implementation of the ssl protocol fails to understand the data sent by the server. Of course i can only "suspect" this cause i don't understand the SSL protocol. The fact is that the code i provided in my opening post WORKS FINE with a lot of servrs. Which means that the SSL authentication works fine and i can read/write from the sslstream. So there must be something wrong with the ssl implementation of irc.discostars.de but as i just said, using mIRC (www.mirc.com) + OpenSSL (www.openssl.org) i can connect to that server.
i've done this:
| |
Console .WriteLine ("Before"); sslStream.AuthenticateAsClient (certName, null, System.Security.Authentication.SslProtocols.Ssl2 | System.Security.Authentication. SslProtocols.Ssl3 | System.Security.Authentication. SslProtocols.Tls, false); Console.WriteLine ("After");
|
and in the console i obtain this:
Before
Received an unexpected EOF or 0 bytes from the transport stream.
Press any key to continue . . .
which means the authentication fails. However in my beginning post i've provided the whole code, so if you want to play with it, just cut and paste it :P