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.
Related
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");
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).
i have done a server using this example socketAsyncEventArgs
in visual studio 2010 and .net 4.0.
Now i'm trying to connect to it from a windows 8 app using StreamSocket but i'm getting a "Acces denied" message.
here is the Client code:
private StreamSocket streamSocket;
public string Server = "192.168.0.101";
public int Port = 9900;
public async void Connect()
{
streamSocket = new StreamSocket();
Connect();
try
{
await streamSocket.ConnectAsync(
new Windows.Networking.HostName(Server),
Port.ToString()); // getting Acces Denied here
DataReader reader = new DataReader(streamSocket.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
while (true)
{
var bytesAvailable = await reader.LoadAsync(1000);
var byteArray = new byte[bytesAvailable];
reader.ReadBytes(byteArray);
}
}
catch (Exception e)
{
MessageBox(e.StackTrace);
}
}
How to fix the problem? Is there another way to send and receive messages using this server?
You are probably also seeing the following as part of your error message:
WinRT information: A network capability is required to access this network resource
This is because you need to add a capability to your application that allows you to access local networks. Double click on the Package.appxmanifest file in your project. Click on the Capabilities tab. Add the Private Networks (Client & Server) capability to your project.
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.
Currently I have an application that receives an uploaded file from my web application. I now need to transfer that file to a file server which happens to be located on the same network (however this might not always be the case).
I was attempting to use the webclient class in C# .NET.
string filePath = "C:\\test\\564.flv";
try
{
WebClient client = new WebClient();
NetworkCredential nc = new NetworkCredential(uName, password);
Uri addy = new Uri("\\\\192.168.1.28\\Files\\test.flv");
client.Credentials = nc;
byte[] arrReturn = client.UploadFile(addy, filePath);
Console.WriteLine(arrReturn.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
The machine located at 192.168.1.28 is a file server and has a share c:\Files.
As of right now I am receiving an error of Login failed bad user name or password, but I can open explorer and type in that path login successfully. I can also login using remote desktop, so I know the user account works.
Any ideas on this error?
Is it possible to transfer a file directly like that? With the webclient class or maybe some other class?
Just use
File.Copy(filepath, "\\\\192.168.1.28\\Files");
A windows fileshare exposed via a UNC path is treated as part of the file system, and has nothing to do with the web.
The credentials used will be that of the ASP.NET worker process, or any impersonation you've enabled. If you can tweak those to get it right, this can be done.
You may run into problems because you are using the IP address instead of the server name (windows trust settings prevent leaving the domain - by using IP you are hiding any domain details). If at all possible, use the server name!
If this is not on the same windows domain, and you are trying to use a different domain account, you will need to specify the username as "[domain_or_machine]\[username]"
If you need to specify explicit credentials, you'll need to look into coding an impersonation solution.
namespace FileUpload
{
public partial class Form1 : Form
{
string fileName = "";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string path = "";
OpenFileDialog fDialog = new OpenFileDialog();
fDialog.Title = "Attach customer proposal document";
fDialog.Filter = "Doc Files|*.doc|Docx File|*.docx|PDF doc|*.pdf";
fDialog.InitialDirectory = #"C:\";
if (fDialog.ShowDialog() == DialogResult.OK)
{
fileName = System.IO.Path.GetFileName(fDialog.FileName);
path = Path.GetDirectoryName(fDialog.FileName);
textBox1.Text = path + "\\" + fileName;
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
WebClient client = new WebClient();
NetworkCredential nc = new NetworkCredential("erandika1986", "123");
Uri addy = new Uri(#"\\192.168.2.4\UploadDocs\"+fileName);
client.Credentials = nc;
byte[] arrReturn = client.UploadFile(addy, textBox1.Text);
MessageBox.Show(arrReturn.ToString());
}
catch (Exception ex1)
{
MessageBox.Show(ex1.Message);
}
}
}
}
when you manually open the IP address (via the RUN command or mapping a network drive), your PC will send your credentials over the pipe and the file server will receive authorization from the DC.
When ASP.Net tries, then it is going to try to use the IIS worker user (unless impersonation is turned on which will list a few other issues). Traditionally, the IIS worker user does not have authorization to work across servers (or even in other folders on the web server).