FTP/SSL Tutorial

Applies to: Rebex Total Pack, Rebex File Transfer Pack, Rebex FTP/SSL

Table of content

#FTP/SSL basics

Rebex FTP/SSL for .NET is a versatile file-transfer component for .NET languages (such as C# or VB.NET). It allows you to transfer files directly from your application using FTPS, an extension of FTP which is quickly becoming a standard for secure FTP. This protocol is also known as FTP over SSL or FTP over TLS and is defined by RFC 4217.

Please note that SSL and TLS are different versions of the same protocol - TLS 1.0 is a name for what was supposed to be SSL 3.1. When we use the term "SSL", we generally mean "SSL or TLS".

back to top...


#Namespaces and assemblies

There are several assemblies you might need to reference in your project to be able to use all features of FTP/SSL for .NET. Rebex.Ftp.dll, Rebex.Common.dll and Rebex.Networking.dll is needed for any FTP operations.

To gain access to all functionality, import the following namespaces in your source files.

C#

using Rebex.Net;
using Rebex.Security.Certificates;

VB.NET

Imports Rebex.Net
Imports Rebex.Security.Certificates

back to top...


#Connecting to an FTP/SSL server using SSL

There are two methods to connect to a secure FTP server:

1) Explicit SSL protection of the FTP session

Client connects to FTP server in a usual non-protected way, usually to port 21 (Ftp.DefaultPort) which is assigned to FTP protocol. When it is desired to protect the connection using SSL, an SSL negotiation is initialized, control connection is secured and all following communication is being protected. Protection of data connections is optional.

C#

// Create an instance of the Ftp class.
Ftp ftp = new Ftp();

// Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit);

// Connection is protected now, we can log in safely.
ftp.Login(username, password);

// Specifies whether protection of transferred data is required.
// Default value of this property is "true", so this is not required.
ftp.SecureTransfers = true;

VB.NET

' Create an instance of the Ftp class.
Dim ftp As New Ftp()

' Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit)

' Connection is protected now, we can log in safely.
ftp.Login(username, password)

' Specifies whether protection of transferred data is required.
' Default value of this property is "true", so this is not required.
ftp.SecureTransfers = True

Explicit protection means that it is possible to secure the connection at any moment. If you don't know whether you will need the protection on not at the connection time, you might want to connect using the ordinary unencrypted FTP protocol and secure the connection later.

C#

Ftp ftp = new Ftp();

// Connect to the server with no protection.
ftp.Connect(hostname, 21);

// Upgrade connection to SSL.
// This method also accepts an argument to specify SSL parameters.
ftp.Secure();

// Connection is protected now, we can log in safely.
ftp.Login(username, password);

VB.NET

Dim ftp As New Ftp()

' Connect to the server with no protection.
ftp.Connect(hostname, 21)

' Upgrade connection to SSL.
' This method also accepts an argument to specify SSL parameters.
ftp.Secure()

' Connection is protected now, we can log in safely.
ftp.Login(username, password)

2) Implicit SSL protection of the FTP session

FTPS protocol was originally assigned a separate port by the IANA (Ftp.DefaultImplicitSslPort = 990). Upon connection to this port, an SSL negotiation starts immediately and the control connection is secured. All data connections are also secured implicitly in the same way. This is similar to the approach used by HTTPS.

This approach is not favored by the IETF and is deprecated. It is supported by Rebex FTP/SSL for interoperability with older servers, but it is strongly recommended to use the explicit protection instead whenever possible.

C#

Ftp ftp = new Ftp();

// Connect securely using implicit SSL.
ftp.Connect(hostname, SslMode.Implicit);

// Connection is protected now, we can log in safely.
ftp.Login(username, password);

VB.NET

Dim ftp As New Ftp()

' Connect securely using implicit SSL.
ftp.Connect(hostname, SslMode.Implicit)

' Connection is protected now, we can log in safely.
ftp.Login(username, password)

back to top...


#Getting information about SSL connection

You can easily get information about the SSL connection using properties of Ftp.TlsSocket.

C#

Ftp ftp = new Ftp();

// Connect securely using explicit SSL and a custom port.
ftp.Connect(hostname, port, SslMode.Explicit);

// The Cipher property contains a lot of
// information about the current cipher
TlsCipher cipher = ftp.TlsSocket.Cipher;
Console.WriteLine("Protocol: {0}", cipher.Protocol);
Console.WriteLine("Cipher: {0}", cipher.CipherAlgorithm);
Console.WriteLine("Key exchange: {0}", cipher.KeyExchangeAlgorithm);
Console.WriteLine("MAC algorithm: {0}", cipher.MacAlgorithm);
Console.WriteLine("All together: {0}", cipher);

// ServerCertificate property provides access
// to server certificate. The first certificate in the chain
// is the server's certificate.
CertificateChain serverCert = ftp.TlsSocket.ServerCertificate;
Console.WriteLine("Subject: {0}", serverCert[0].GetSubject());
Console.WriteLine("Issuer: {0}", serverCert[0].GetIssuer());

VB.NET

Dim ftp As New Ftp()

' Connect securely using explicit SSL and a custom port.
ftp.Connect(hostname, port, SslMode.Explicit)

' The Cipher property contains a lot of
' information about the current cipher
Dim cipher As TlsCipher = ftp.TlsSocket.Cipher
Console.WriteLine("Protocol: {0}", cipher.Protocol)
Console.WriteLine("Cipher: {0}", cipher.CipherAlgorithm)
Console.WriteLine("Key exchange: {0}", cipher.KeyExchangeAlgorithm)
Console.WriteLine("MAC algorithm: {0}", cipher.MacAlgorithm)
Console.WriteLine("All together: {0}", cipher)

' ServerCertificate property provides access
' to server certificate chain. The first certificate in the chain
' is the server's certificate.
Dim serverCert As CertificateChain = ftp.TlsSocket.ServerCertificate
Console.WriteLine("Subject: {0}", serverCert(0).GetSubject())
Console.WriteLine("Issuer: {0}", serverCert(0).GetIssuer())

back to top...


#Specifying SSL parameters

It is possible to affect many aspects of SSL such as specifying which protocol versions to use or what cipher suites to allow.

It is a good idea to disable weak cipher suites and only allowing the strong ones.

C#

// Specify desired arguments via Ftp's Settings property

// Only use suites that are currently considered secure.
ftp.Settings.SslAllowedSuites = TlsCipherSuite.Secure;
// Allow both SSL 3.0 and TLS 1.0 protocols to be used.
ftp.Settings.SslAllowedVersions = TlsVersion.SSL30 | TlsVersion.TLS10;
// You can also specify the common name of
// the FTP server if it differs from its hostname.
ftp.Settings.SslServerName = hostname;

// Connect securely using explicit SSL.
// The third argument refers to the parameters class.
ftp.Connect(hostname, SslMode.Explicit);

// Connection is protected now, we can log in safely.
ftp.Login(username, password);

VB.NET

' Specify desired arguments via Ftp's Settings property

' Only use suites that are currently considered secure.
ftp.Settings.SslAllowedSuites = TlsCipherSuite.Secure
' Allow both SSL 3.0 and TLS 1.0 protocols to be used.
ftp.Settings.SslAllowedVersions = TlsVersion.SSL30 Or TlsVersion.TLS10
' You can also specify the common name of
' the FTP server if it differs from its hostname.
ftp.Settings.SslServerName = hostname

' Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit)

' Connection is protected now, we can log in safely.
ftp.Login(username, password)

Specifying the supported set of ciphers one by one is also possible. If you only accept DSA certificates and AES encryption, you can have that.

C#

// Only use the specified cipher suites.
ftp.Settings.SslAllowedSuites =
    TlsCipherSuite.DHE_DSS_WITH_AES_256_CBC_SHA |
    TlsCipherSuite.DHE_DSS_WITH_AES_128_CBC_SHA;

VB.NET

' Only use the specified cipher suites.
ftp.Settings.SslAllowedSuites =
 TlsCipherSuite.DHE_DSS_WITH_AES_256_CBC_SHA Or
 TlsCipherSuite.DHE_DSS_WITH_AES_128_CBC_SHA

back to top...


#Validating and examining server certificates

Even though Rebex FTP/SSL validates server certificate automatically by default, it is often desired to extend this process, for example by adding the ability to ask the user whether to accept or reject the server certificate. In other scenarios, you might want to use your own code to decide. This is possible by implementing a custom certificate validator.

C#

// A custom certificate verification handler.
private void ftp_ValidatingCertificate(object sender, SslCertificateValidationEventArgs e)
{
    // Use the built-in validation method to validate the chain.
    // It is up to you to use another validation method if needed.
    ValidationResult res = e.CertificateChain.Validate(e.ServerName, 0);

    // Accept the certificate if the chain is valid.
    if (res.Valid)
        e.Accept();

    // If the chain is not valid, let's display the certificate
    // information and validation status to the user and let
    // him decide what to do.

    Certificate cert = e.CertificateChain[0];
    bool shouldAccept = SomeCustomDialog(cert, res.Status);

    if (shouldAccept)
        e.Accept();
    else
        e.Reject();
}
Ftp ftp = new Ftp();

// Register a custom handler of ValidatingCertificate event.
ftp.ValidatingCertificate += ftp_ValidatingCertificate;

// Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit);

// Connection is protected now, we can log in safely.
ftp.Login(username, password);

VB.NET

' A custom certificate verification handler.
Private Sub ftp_ValidatingCertificate(sender As Object, e As SslCertificateValidationEventArgs)
    ' Use the built-in validation method to validate the chain.
    ' It is up to you to use another validation method if needed.
    Dim res As ValidationResult = e.CertificateChain.Validate(e.ServerName, 0)

    ' Accept the certificate if the chain is valid.
    If res.Valid Then
        e.Accept()
    End If

    ' If the chain is not valid, let's display the certificate
    ' information and validation status to the user and let
    ' him decide what to do.

    Dim cert As Certificate = e.CertificateChain(0)
    Dim shouldAccept As Boolean = SomeCustomDialog(cert, res.Status)

    If shouldAccept Then
        e.Accept()
    Else
        e.Reject()
    End If
End Sub
Dim ftp As New Ftp()

' Register a custom handler of ValidatingCertificate event.
AddHandler ftp.ValidatingCertificate, AddressOf ftp_ValidatingCertificate

' Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit)

' Connection is protected now, we can log in safely.
ftp.Login(username, password)

back to top...


#Authenticating the client using a certificate

FTPS server might be configured to request the client to authenticate using its certificate during SSL negotiation. Client either complies or informs the server that no it has no suitable certificate available. In the latter case, the server can optionally refuse to proceed negotiating. Rebex FTP/SSL for .NET makes it possible to select one of the built-in certificate request handlers or to implement a custom handler if they are not sufficient.

By default, client authentication is disabled - certificate request handler is set to the built-in CertificateRequestHandler.NoCertificate handler that does not try to find any certificate and just informs the server that no certificate is available.

However, client authentication can be enabled easily by using the second built-in certificate request handler that is able to searche the user's certificate store for a suitable certificate with a private key, and if one is found, it is used to authenticate the client:

C#

Ftp ftp = new Ftp();

// Set the certificate request handler to
// CertificateRequestHandler.StoreSearch.
ftp.Settings.SslClientCertificateRequestHandler = CertificateRequestHandler.StoreSearch;

// Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit);

// Connection is protected now, we can log in safely.
// Some servers may not require login if the client
// successfully authenticated itself using a certificate
// known to the server - there is no need to call the Login
// method in these cases.
ftp.Login(username, password);

VB.NET

Dim ftp As New Ftp()

' Set the certificate request handler to
' CertificateRequestHandler.StoreSearch.
ftp.Settings.SslClientCertificateRequestHandler = CertificateRequestHandler.StoreSearch

' Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit)

' Connection is protected now, we can log in safely.
' Some servers may not require login if the client
' successfully authenticated itself using a certificate
' known to the server - there is no need to call the Login
' method in these cases.
ftp.Login(username, password)

Another built-in certificate request handler is based on certificate chain and makes it possible to easily authenticate a user using a client certificate stored in a .PFX/.P12 (PKCS#12) file:

C#

Ftp ftp = new Ftp();

// Load a certificate chain from a .PFX/.P12 file
// that contains a certificate and its private key.
CertificateChain certificateChain = CertificateChain.LoadPfx(pfxCertPath, pfxPassword);

// Assing a certificate request handler based on
// the chain loaded from the PFX file.
ftp.Settings.SslClientCertificateRequestHandler = CertificateRequestHandler.CreateRequestHandler(certificateChain);

// Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit);

// Connection is protected now, we can log in safely.
// Some servers may not require login if the client
// successfully authenticated itself using a certificate
// known to the server - there is no need to call the Login
// method in these cases.
ftp.Login(username, password);

VB.NET

Dim ftp As New Ftp()

' Load a certificate chain from a .PFX/.P12 file
' that contains a certificate and its private key.
Dim certificateChain As CertificateChain = certificateChain.LoadPfx(pfxCertPath, pfxPassword)

' Assing a certificate request handler based on
' the chain loaded from the PFX file.
ftp.Settings.SslClientCertificateRequestHandler = CertificateRequestHandler.CreateRequestHandler(certificateChain)

' Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit)

' Connection is protected now, we can log in safely.
' Some servers may not require login if the client
' successfully authenticated itself using a certificate
' known to the server - there is no need to call the Login
' method in these cases.
ftp.Login(username, password)

If you need to use another method of selecting a suitable certificate or if a GUI should be presented to the user to let him select the certificate, a custom certificate handler can be used instead. The following sample handler will load a certificate from a PKCS#12 file as well, but it can be easily modified to do something else:

C#

// A custom certificate request handler class.
// Implements ICertificateRequestHandler interface.
public class CustomRequestHandler : ICertificateRequestHandler
{
    // This method gets called during the SSL handshake
    // process if the server requests the client's certificate.
    public CertificateChain Request(
        TlsSocket socket,
        DistinguishedName[] issuers)
    {
        // Load the certificate with a private key from a PFX file.
        string path = "myCertificate.pfx";
        Certificate cert = Certificate.LoadPfx(path, "password");

        // We actually need a certificate chain, so let's build one.
        CertificateChain chain = CertificateChain.BuildFrom(cert);
        return chain;
    }
}
Ftp ftp = new Ftp();

// Set the certificate request handler to an instance
// of CustomVerifier.
ftp.Settings.SslClientCertificateRequestHandler = new CustomRequestHandler();

// Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit);

// Connection is protected now, we can log in safely.
// Some servers may not require login if the client
// successfully authenticated itself using a certificate
// known to the server - there is no need to call the Login
// method in these cases.
ftp.Login(username, password);

VB.NET

' A custom certificate request handler class.
' Implements ICertificateRequestHandler interface.
Public Class CustomRequestHandler
    Implements ICertificateRequestHandler

    ' This method gets called during the SSL handshake
    ' process if the server requests the client's certificate.
    Public Overloads Function Request( _
     ByVal socket As TlsSocket, _
     ByVal issuers() As DistinguishedName) _
     As CertificateChain _
     Implements ICertificateRequestHandler.Request

        ' Load the certificate with a private key from a PFX file.
        Dim path As String = "myCertificate.pfx"
        Dim cert As Certificate = Certificate.LoadPfx(path, "password")

        ' We actually need a certificate chain, so let's build one.
        Dim chain As CertificateChain = CertificateChain.BuildFrom(cert)
        Return chain
    End Function
End Class
Dim ftp As New Ftp()

' Set the certificate request handler to an instance
' of CustomVerifier.
ftp.Settings.SslClientCertificateRequestHandler = New CustomRequestHandler()

' Connect securely using explicit SSL.
ftp.Connect(hostname, SslMode.Explicit)

' Connection is protected now, we can log in safely.
' Some servers may not require login if the client
' successfully authenticated itself using a certificate
' known to the server - there is no need to call the Login
' method in these cases.
ftp.Login(username, password)

Check out the FTP Client sample source code for an advanced certificate request handler that presents a GUI to the user and lets him choose the certificate to use.

back to top...


Back to tutorial list...