Raw FTP SSL with C# - c#

I'm trying to understand how SSL works. In my wish to make a small FTP client which supports SSL I've run into some problems:
TcpClient FtpConnection = new TcpClient(FtpServer, FtpPort);
NetworkStream FtpStream = FtpConnection.GetStream();
StreamReader FtpReader = new StreamReader(FtpStream);
FtpWriter = new StreamWriter(IrcStream);
send_cmd("AUTH SSL");
send_cmd is just a FtpWriter.WriteLine(text); FtpWriter.Flush(); function.
My "problem" is this: First I need to make a (non-ssl) connection to the FTP, then tell it to do a ssl connection (AUTH SSL), and I would guess I then need to make a new connection - something like:
TcpClient client = new TcpClient(FtpServer, FtpPort);
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
try
{
sslStream.AuthenticateAsClient("foobar");
}
catch (AuthenticationException e)
{
MessageBox.Show("Authentication failed - closing the connection.");
client.Close();
return;
}
Taken from msdn.
I keep dying on handshake failed due to unexpected packet format (which I've tried googling, but all say it's because the author has connected to a wrong port), which I take as: The connection is not ssl until AUTH SSL is send to it. So my question is, how would i go about making this a "hybrid" connection so I can make an SSL connection to the server?
Any help is greatly appreciated!

Using a library like that is the opposite of what I wanted. Since I found so few hits when searching the web, I'll post what I figured out:
Building a C# ftp client is basically like so:
TcpClient blabla = new TcpClient("some.host", 21);
NetworkStream blabla_stream = blabla.GetStream();
StreamReader unsecure_reader = new StreamReader(blabla_stream);
StreamWriter blabla_writer = new StreamWriter(blabla_stream);
blabla_writer.WriteLine("AUTH SSL");
string response = "";
while ((response = unsecure_reader.ReadLine()) != null)
{
if (response.Substring(0,3) == "234")
{
SslStream ssl_connection = new SslStream(blabla.GetStream(), false, new RemoteCertificateValidationCallback(validate_certificate), null);
ssl_connection.AuthenticateAsClient("");
StreamReader ssl_stream = new StreamReader(ssl_connection);
ftp_writer = new StreamWriter(ssl_connection);
}
}
where validate_certificate is a function based on msdn's (you can google it and mod it easily yourself).
For more info see RFC 4217 and 2228.

http://ftps.codeplex.com/
This project contains every pieces you need.

Related

FTP Connection issue- using FluentFTP for port 990 -TLS

I am trying download file through FTPS connection with port 990 (TLS) using FluentFTP.
But the code is not able to establish connection and showing exception as "The remote certificate is invalid according to the validation procedure."
The FTP server is connecting properly when I use FileZilla FTP tool manually (showing as it is connected through ftps over TLS (Implicit)
FtpClient fclient = new FtpClient(hostname, username, password);
fclient.EncryptionMode = FtpEncryptionMode.Implicit;
fclient.SslProtocols = SslProtocols.Tls12; //Also tried with TLS1 and TLS
fclient.Port = 990;
fclient.Connect();
Try this (taken from ConnectFTPSCertificate.cs example of FluentFTP). The important part is the callback OnValidateCertificate.
public static async Task ConnectFTPSCertificateAsync() {
var token = new CancellationToken();
using (var conn = new FtpClient("127.0.0.1", "ftptest", "ftptest")) {
conn.EncryptionMode = FtpEncryptionMode.Explicit;
conn.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
await conn.ConnectAsync(token);
}
}
private static void OnValidateCertificate(FtpClient control, FtpSslValidationEventArgs e) {
if (e.PolicyErrors == System.Net.Security.SslPolicyErrors.None) {
e.Accept = true;
}
else {
// add logic to test if certificate is valid here
// lookup the "Certificate" and "Chain" properties
e.Accept = false;
}
}
I experienced the same issue.
Pay attention that fluentFTP supports only external interfaces and not implicit
I also tried ftpWebRequest without success.
Try using winSCP.

C# - Implement Secure Web Socket

I would like to ask if you know how to implement Secure Web Socket with .Net.
I've implemented ws:// and everything ok but I've no idea how to switch to wss://.
Thanks in advance.
You could try Fleck
Fleck is a WebSocket server implementation in C#
From their examples:
var server = new WebSocketServer("wss://0.0.0.0:8431");
server.Certificate = new X509Certificate2("MyCert.pfx");
server.Start(socket =>
{
//...use as normal
});
This question is very old but here's how i got my C# server accept an SSL connection from the client (js code running on Chrome / Firefox).
Assuming you already have a working and valid certificate (in my case the same certificate working to serve SSL on my Apache webserver), signed by a trusted CA (in my case, letsencrypt.org, which let you request a certificate for free), this is an excerpt from working code:
public static X509Certificate2 serverCertificate = null;
public Server(string ip_addr, int port)
{
serverCertificate = GetCertificateFromStore("CN=mydomain.com");
string resultsTrue = serverCertificate.ToString(true); // Debugging purposes
bool hasPrivateKey = serverCertificate.HasPrivateKey; // Debugging purposes (MUST return true)
Console.WriteLine("Certificate validation results: " + resultsTrue);
Console.WriteLine("Has private key? " + hasPrivateKey);
server = new TcpListener(IPAddress.Parse(ip_addr), port);
server.Start();
Console.WriteLine("Server has started on ip: " + ip_addr + ":"+port + " - Waiting for a connection...", Environment.NewLine);
}
public class ClientHandler
{
TcpClient client { get; set; }
//NetworkStream stream { get; set; } // Old plain non-secure tcp stream
SslStream stream { get; set; } // New secure tcp stream
....
public ClientHandler(TcpClient client, string room_id)
{
....
stream = new SslStream(client.GetStream(), false);
try
{
stream.AuthenticateAsServer(Server.serverCertificate, clientCertificateRequired: false, checkCertificateRevocation: false);
// Set timeouts for the read and write to 5 seconds.
stream.ReadTimeout = 5000;
stream.WriteTimeout = 5000;
}
catch (Exception ex)
{
Console.WriteLine("Error during SSL authentication with the client:" + ex);
return;
}
}
}
The tricky part is that class X509Certificate2 needs to retrieve the certificate not from file but from your local keystore.
Also you need both the certificate file AND your private key for SSL to work.
I'm developing on Linux and Mono.Net but it should not change much on other platforms. The tools i needed were: openssl and certmgr (mono certificate manager).
To create the .pfx file containing the cert & the private key:
openssl pkcs12 -export -in yourcertfile.cer -inkey yourprivatekeyfile.pem -out finalfile.pfx
To add the file obtained to my local store:
certmgr -add -c -m Trust finalfile.pfx
Finally, you can edit your client side connection code to point to the same domain you're hosting your server (which should be the same domain reported in your certificate).
This:
var mySocket = new WebSocket("ws://127.0.0.1:5050");
Becomes:
var mySocket = new WebSocket("wss://yourdomain.com:5050");
Keep in mind that, once you've implemented SSL, you'll have to revise the whole networking code, since you're adding overhead to your TCP stream and you must take it into account when parsing the bytes and the bits to find and decode the headers.
This is where i'm stuck myself but beside that, SSL connection works great :)
If you use WebSocketSharp-NonPreRelease Package to develop the websocket you can simply add your certificate using below code
var wssv = new WebSocketServer (5963, true);
wssv.SslConfiguration.ServerCertificate =
new X509Certificate2 ("/path/to/cert.pfx", "password for cert.pfx");

C# socket hangs when receive in loop - python as socket server

I'm familiar with C#, and know some python. Recent days I'm learning the book Programming Python, 4th Edition and have run the very basic socket samples: echo-server.py and echo-client.py
They work well on my Windows, python 3.x.
python server:
from socket import *
myHost = 'localhost'
myPort = 50007
sockobj = socket(AF_INET, SOCK_STREAM)
sockobj.bind((myHost, myPort))
sockobj.listen(5)
while True:
connection, address = sockobj.accept()
print('Server connected by', address)
while True:
data = connection.recv(1024)
if not data: break
connection.send(b'Echo=>' + data)
connection.close()
Now I want to learn socket in C# too, so I wrote a C# .net framework 4.5 socket client, expecting to receive and show what echo-client.py does.
I got the C# demo from msdn and made some refactor to reduce code size.
public static void Main(string[] args)
{
string server = "localhost";
int port = 50007;
string request = "GET / HTTP/1.1\r\nHost: " + server +
"\r\nConnection: Close\r\n\r\n";
Byte[] sent = Encoding.ASCII.GetBytes(request);
Byte[] recv = new Byte[256];
IPHostEntry hostEntry = Dns.GetHostEntry(server);
IPEndPoint ipe = new IPEndPoint(hostEntry.AddressList[1], port);
Socket s =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Connect(ipe);
s.Send(sent, sent.Length, 0);
int bytes = 0;
string page = "recived:\r\n";
//do
{
bytes = s.Receive(recv, recv.Length, 0);
page = page + Encoding.ASCII.GetString(recv, 0, bytes);
}
//while (bytes > 0);
Console.WriteLine(page);
Console.WriteLine("result");
Console.ReadKey();
}
My test steps:
If I set up a web site using local IIS, such as
http://localhost:801, then above code can show the homepage html
contents, this means my C# code is working.
Run echo-server.py, and change C# code's port to 50007, then run,
nothing output in console, and application does not exit, if I place a break point within the loop, I can see the loop has only run once. The python server did output some log saying C# is connecting.
Comment do while loop(as commented in code), this time the output is exactly same as echo-client.py(expected).
So I'm wondering what's wrong when I'm using do while loop?

Connect an C# application thats running sockets using JAVASCRIPT

Hey i was wondering if you could help me
I'm creating an android application in html5 and java script.
There are a server that is created on c# that is listing connection.
I can connect the 2 apps together but get i can get the c# app to reply to my android application using javascript.
here is my server code
public void Listeners()
{
Socket socketForClient = tcpListener.AcceptSocket();
if (socketForClient.Connected)
{
nr_connections = nr_connections + 1;
nr_qry = nr_qry + 1;
SetText("");
SetText("New Connection.");
NetworkStream networkStream = new NetworkStream(socketForClient);
StreamWriter streamWriter = new StreamWriter(networkStream);
StreamReader streamReader = new StreamReader(networkStream);
streamWriter.Flush();
string GettheString = streamReader.ReadLine();
if (GettheString == "server_status")
{
SetText("Checking Server Status.");
streamWriter.WriteLine("Online");
streamWriter.Close();
streamReader.Close();
networkStream.Close();
}
}
socketForClient.Close();
SetText("Connection Closed...");
Thread newThread = new Thread(new ThreadStart(Listeners));
newThread.Start();
nr_connections = nr_connections - 1;
}
and my javascript code
function connect ()
{
try
{
var connection = new WebSocket('ws://105.237.125.247:8');
connection.onopen = function ()
{
connection.send('server_status');
};
connection.onmessage = function (event) {
alert(event.data);
}
}
catch(Exeption)
{
alert("Check Connection");
}
}
Im getting data from the android app but can send back to the javascript file
Web-sockets is a protocol that sits on top of a regular transport (such as a socket); basically, you need a web-socket library. If you are using recent versions of Windows, then much of this is baked into HTTP.SYS, and available via HttpListnener (in particular, AcceptWebSocketAsync on a context). However, alternative web-socket libraries are available, or can be written from scratch if you so choose.

SslStream.AuthenticateAsServer exception - The server mode SSL must use a certificate with the associated private key

I am developing a proxy server application similar to CCProxy. Its working fine for HTTP but not HTTPS. Its throwing exception when AuthenticateAsServer() method is called on SslStream object.
I also don't know whether I have supplied proper certificate, I don't know how to create a certificate. I just provided the certificate which came with the code that I downloaded online.
Here is the code:
private static void DoHttpProcessing(TcpClient client)
{
Stream clientStream = client.GetStream();
Stream outStream = clientStream;
SslStream sslStream = null;
StreamReader clientStreamReader = new StreamReader(clientStream);
CacheEntry cacheEntry = null;
MemoryStream cacheStream = null;
if (Server.DumpHeaders || Server.DumpPostData || Server.DumpResponseData)
{
Monitor.TryEnter(_outputLockObj, TimeSpan.FromMilliseconds(-1.0));
}
try
{
//read the first line HTTP command
String httpCmd = clientStreamReader.ReadLine();
if (String.IsNullOrEmpty(httpCmd))
{
clientStreamReader.Close();
clientStream.Close();
return;
}
//break up the line into three components
String[] splitBuffer = httpCmd.Split(spaceSplit, 3);
String method = splitBuffer[0];
String remoteUri = splitBuffer[1];
Version version = new Version(1, 0);
HttpWebRequest webReq;
HttpWebResponse response = null;
if (splitBuffer[0].ToUpper() == "CONNECT")
{
remoteUri = "https://" + splitBuffer[1];
while (!String.IsNullOrEmpty(clientStreamReader.ReadLine())) ;
StreamWriter connectStreamWriter = new StreamWriter(clientStream);
connectStreamWriter.WriteLine("HTTP/1.0 200 Connection established");
connectStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString()));
connectStreamWriter.WriteLine("Proxy-agent: matt-dot-net");
connectStreamWriter.WriteLine();
connectStreamWriter.Flush();
sslStream = new SslStream(clientStream, false);
try
{
// HERE I RECEIVE EXCEPTION
sslStream.AuthenticateAsServer(_certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
sslStream.Close();
clientStreamReader.Close();
connectStreamWriter.Close();
clientStream.Close();
return;
}//further code goes here...
Also, instead of sslStream.AuthenticateAsServer, if I use ssStream.AuthenticateAsClient method I get AuthenticationException with message "A call to SSPI failed, see inner exception." and InnerException gives message as "The message received was unexpected or badly formatted"
When I am using sslstream.AuthenticateAsServer() method, I need to create certificate for each new HTTPS host and pass it with this method. If I provide the self signed certificate, the request succeeds. But problem is, for how many new HTTPS requests will I keep creating certificates manually and assign it to AuthenticateAsServer()?
For the serverside certificate, most certificates correspond to a FQDN (so server1.localhost.local), although there can be wildcard certs (*.localhost.local). When you use AuthenticateAsClient method, that could be one of two things, 1) The Certificate doesnt have the Extended Key Usage for Client Authentication or 2) you didnt pass the right password for it to read the cert/private key. To get past both these hurdles rather quickly i would suggest creating an OpenSSL CA and then generating a CA and Server Cert. There is tons of documentation on how to do this and should take 30 minutes tops for someone who has never created one before....(Also i would suggest exporting the cert into pkcs12 extension for the CA to be chained in with the Server Cert).

Categories