A call to SSPI failed, see inner exception using F

2019-08-07 00:57发布

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 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.

0条回答
登录 后发表回答