Patrick
Patrick

Reputation: 2781

FTP Download File generate the error: A call to SSPI failed

I am trying to download a file from my FTP Server but from my production server (from my laptop I am able to download the file) I get the error "A call to SSPI failed" and the inner exception "The message received was unexpected or badly formatted". This my code:

var ftpServer = "ftp://xxx.yyy.zz/";
var ftpUsername = "aaaaa";
var ftpPassword = "bbbbb";
var downloadedFilePath = "c:\\temp\\";
var downloadedFileName = "file.xls";                      
FtpWebRequest request = null;

ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol | SecurityProtocolType.Tls12;

ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
                    return true;
                };

// Get the object used to communicate with the server.
request = (FtpWebRequest)WebRequest.Create(ftpServer + "file_on_ftp_server.xls");

// download the file
request.Method = WebRequestMethods.Ftp.DownloadFile;

request.Credentials = new NetworkCredential(ftpUsername, ftpPassword);

request.EnableSsl = true;
request.KeepAlive = false;

FtpWebResponse response = (FtpWebResponse)request.GetResponse();    // <--- ERROR

Stream responseStream = response.GetResponseStream();
FileStream writer = new FileStream(downloadedFilePath + downloadedFileName, FileMode.Create);

Upvotes: 5

Views: 1309

Answers (4)

MD. RAKIB HASAN
MD. RAKIB HASAN

Reputation: 3956

The TLS handshake was failing because two servers were unable to agree on a common cipher suite.

IIS Crypto to enable additional cipher suites on web app's server. downloaded and ran IIS Crypto, checkmarked additional cipher suites on its Cipher Suites tab after then restarted the machine.

If diagnose failure, I'd recommend installing Wireshark on the machine with your .NET Core app. If TLS Handshake Failure again,a message like: Alert (Level: Fatal, Description: Handshake Failure) Some cipher suites are more secure than others, so check ref link may help to solve your problem.

temporary solution:
set the minimum key length for schannel using windows registry:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman]
"ClientMinKeyBitLength"=dword:00000200

Ref: Link1, link2, link3 ,Link4

Upvotes: 2

Olivier
Olivier

Reputation: 18122

SSPI is a Windows component. If you are on Windows 2008, it means it's very old.

The error "The message received was unexpected or badly formatted" seems to indicate that the server certificate uses an unsupported format (for instance, uses an unknown cipher), and thus can't be processed by the SSPI layer.

You have several solutions:

  • Upgrade Windows
  • Downgrade the server certificate
  • Don't use SSL
  • Use an alternative FTP library that does not rely on SSPI

Upvotes: 2

ale91
ale91

Reputation: 376

Based on the previous suggestions your code should look like this:

var ftpServer = "ftp://xxx.yyy.zz/";
var ftpUsername = "aaaaa";
var ftpPassword = "bbbbb";
var downloadedFilePath = "c:\\temp\\";
var downloadedFileName = "file.xls";                      
var certName = "MyCertName"   //Use yours
var password = "MyCertPassword";   //Use yours
FtpWebRequest request = null;

ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol | SecurityProtocolType.Tls12;

ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
   return true;
};

//Load certificates (one or more)
X509Certificate2Collection certificates = new X509Certificate2Collection();
    certificates.Import(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

// Get the object used to communicate with the server.
request = (FtpWebRequest)WebRequest.Create(ftpServer + "file_on_ftp_server.xls");

// download the file
request.Method = WebRequestMethods.Ftp.DownloadFile;

request.Credentials = new NetworkCredential(ftpUsername, ftpPassword);

request.ClientCertificates = certificates;   //Use certificates

request.EnableSsl = true;
request.KeepAlive = false;

FtpWebResponse response = (FtpWebResponse)request.GetResponse();    // <--- ERROR

Stream responseStream = response.GetResponseStream();
FileStream writer = new FileStream(downloadedFilePath + downloadedFileName, FileMode.Create);

Note: I have not tested the solution because I don't have an environment to test it on

Upvotes: 2

To use SSL certificate inside .Net framework we need to provide both certificate and its corresponding private key together. To achieve this we need to use p12(.pfx) file which combined this two. In my project, I have used self-signed certificate using OpenSSL so I used below command to combine certificate and private key

pkcs12 -export -out ca.pfx -inkey ca.key -in ca.crt

pkcs12 -export -out client.pfx -inkey client.key -in client.crt

which will create p12(.pfx) file for each certificate. Then used them into your code like below .

see below lonk for more information

Reference

maybe this link also help you .

Good luck

Upvotes: 2

Related Questions