FTPS over TLS/SSL using C#

One of the projects I’m working on has a requirement to send a document over a secure FTP connection. The .NET framework has a built-in class to handle FTP (FTPWebRequest) so that was a good starting point.

The documentation for FTPWebRequest does not provide a great deal of detail on securing the communications between the client and the server. There is simply a boolean property named EnableSSL to turn the encryption on or off. Sounded pretty simple, so here’s what I came up with for my upload method:

public bool UploadFile(Uri serverUri, string userName, string password, string fileName) { // the serverUri should start with the ftp:// scheme. if (serverUri.Scheme != Uri.UriSchemeFtp) return false; try { // get the object used to communicate with the server. FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri); request.EnableSsl = true; request.Credentials = new NetworkCredential(userName, password); request.Method = WebRequestMethods.Ftp.UploadFile; // read file into byte array StreamReader sourceStream = new StreamReader(fileName); byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd()); sourceStream.Close(); request.ContentLength = fileContents.Length; // send bytes to server Stream requestStream = request.GetRequestStream(); requestStream.Write(fileContents, 0, fileContents.Length); requestStream.Close(); FtpWebResponse response = (FtpWebResponse)request.GetResponse(); Console.WriteLine("Response status: {0}", response.StatusDescription); } catch (Exception exc) { throw exc; } return true; }

When I ran my app with that method, things didn’t work quite like I wanted them to. Here’s the error I ended up with: “System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.”

The problem is there is no validation procedure. None of the MSDN articles I read said anything about certificate validation. So after much googling, I finally found the missing piece of code in a forum post. So I added a validation procedure and assigned it as the ServicePointManager.ServerCertificateValidationCallback.

public Program() { ServicePointManager.ServerCertificateValidationCallback = AcceptAllCertificatePolicy; } public bool AcceptAllCertificatePolicy(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; }

With that, my secure FTP was a success! Of course, in real-world applications you will want to do some actual validation of the server certificate, but I’ll leave that as an exercise for the reader.


About Martin Witters