I am setting up an FTP Server (FileZilla
) and using the netftp codeplex project
System.Net.FtpClient
to connect to it over SSL
/TLS
using an X509Certificate2
.
- I've downloaded
FileZilla Server
from sourceforge. - I've downloaded
System.Net.FtpClient v14.06.17
from codeplex.
I think I have isolated the problem, but maybe someone has some additional thoughts as to the underlying cause. A workaround is provided at the bottom of this post.
An exception occurs calling client.GetListing()
and client.GetNameListing()
, however, uploading (OpenWrite
) and downloading (OpenRead
) both work fine. I've tested many versions of FileZilla
to isolate what version it started breaking.
- 0.9.42 works (2013-12-16)
- 0.9.43 bad (2014-01-02)
- 0.9.46 bad (2014-08-03)
- 0.9.50 bad (2015-03-19) - current
The exception that occurs is:
- outer message:
A call to SSPI failed, see inner exception.
- inner message:
The message received was unexpected or badly formatted
The C# code sample that causes the error:
FtpClient client = new FtpClient();
client.Credentials = new NetworkCredential("blah", "blah123");
client.Host = "127.0.0.1";
client.Port = 21;
client.DataConnectionEncryption = true;
client.EncryptionMode = FtpEncryptionMode.Explicit;
//client.ClientCertificates.Add(cert); // tried both with and without
client.ValidateCertificate += (cli, e) => { e.Accept = true; };
client.Connect();
var list = client.GetNameListing(); // exception on this line
On the Codeplex Documentation page, jptrosclair
wrote:
You do not use pem certificates, use p12 instead. See this Stack Overflow thread for more information. If you get SPPI exceptions with an inner exception about an unexpected or badly formatted message, you are probably using the wrong type of certificate.
The link refers to asp.net
, not FileZilla
. My guess is that IIS
doesn't support PEM
and was most likely sending a bunch of gibberish through the stream. However, if you use a certificate format that your server supports, then there should be no problem. As far as I have read, FileZilla
only supports PEM
format (or CRT/CER
which are still PEM
format).
Also, this doesn't explain why OpenRead
and OpenWrite
succeed, but GetListing
and GetNameListing
fail.
Regardless, I still tested multiple different certificate generation tools, including FileZilla's
built-in generator, C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\makecert.exe
, and OpenSSL (windows)
. The problem still persisted.
Here is a link similar discussion from skovachev
https://netftp.codeplex.com/discussions/535815
His workaround was to clone the connection before getting the listing.
Workaround:
I've tested the following with all FileZilla
versions listed above. The fix is to download the System.Net.FtpClient
source code from codeplex
and in the FtpSocketStream.cs
class edit the following method:
public void ActivateEncryption(string targethost, X509CertificateCollection clientCerts)
change:
m_sslStream.AuthenticateAsClient(targethost, clientCerts, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, true);
to:
m_sslStream.AuthenticateAsClient(targethost, clientCerts, SslProtocols.Tls | SslProtocols.Ssl3, true);
(Basically just remove the Ssl2
flag).
My guess is something changed in FileZilla v0.9.43
when the Ssl2
flag is set when connecting to the server. It is strange that the first time AuthenticateAsClient
is called it will succeed, but the second time it will fail.
As for uploading and downloading succeeding, the default EnableThreadSafeDataConnections
is true, which causes the client to be cloned and reconnect to the server. However, GetListing
and GetNameListing
do not clone the connection. Putting a breakpoint in the ActivateEncryption
method, the AuthenticateAsClient
will be called multiple times. Maybe there is some connection pooling happening under the hood in the SslStream
class and multiple AuthenticateAsClient
are causing problems. It's worth noting that the FtpClient.ValidateCertificate
event is only called once even though AuthenticateAsClient
is called twice. This gives some evidence of some caching is happening.