Example 2: Server-Validating Client

This example illustrates the use of ProFTPClient in explicit FTPS mode with server validation.

The example performs the following operations:

  1. Loads server certificate.
  2. Connects to the server in plain FTP mode.
  3. Switches to explicit FTPS mode.
  4. Logs in.
  5. Lists directory contents.
  6. Puts a file to the server.
  7. Lists directory contents.
  8. Gets the same file back from the server.
  9. Lists directory contents.
  10. Disconnects.

You can view the source-code here.

INSTRUCTIONS:

  1. Make sure you have a working FTP server with FTPS enabled.
    You may like to use EDT's free FTP/FTPS server, edtFTPD, for this purpose.
    To test that the server is set up correctly, EDT recommends the FTP/FTPS client FileZilla.
  2. Install the server's certificate on your machine. On Windows, this may be done by going to the Control Panel, selecting Internet Options, choosing the Content tag, and clicking the Certificates button. This will bring up the Certificates dialog. Click the Import button and go through the wizard (note that the certificate may be in CER format). On the Certificate Store page of the wizard, choose Trusted Root Certification Authorities as the Certificate Store.
  3. Open a console window.
  4. Change to the examples/Ex2_ServerValidatingClient directory.
  5. Make sure that the C# compiler, csc.exe, is in your PATH.
  6. Run the example by:

    	run host-name username password filename (hostname-checking)
                    

    where

    host-name is the address/name of the FTP server.
    username is the username of the user account on the FTP server.
    password is the password of the user account on the FTP server.
    filename is the name of the ASCII file in the current dir you wish to transfer (less than 10K in size for the trial).
    hostname-checking (optional) - see below.

    The final argument is optional and should be left out initially. It determines whether or not host-name checking is enabled. Possible values are on and off. By default host-name checking is enabled (i.e. on). More details on this will be given later.

  7. Verify that the output looks something like this:

    INFO [ServerValidatingClient] 26 Jan 2005 16:45:27.462 : Creating FTPS (explicit) client
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:27.482 : Host-name checking enabled
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:27.482 : Connecting to server LOCALHOST
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:28.573 : Switching to FTPS (explicit mode)
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:29.044 : Logging in with username=test
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:29.084 : Setting up passive, ASCII transfers
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:29.084 : Directory before put:
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:29.675 :   no files
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:29.675 : Putting ServerValidatingClient.exe to server
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:29.995 : Directory after put:
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:30.336 :   -rw-r--r--   1 SYSTEM   None        16235 Jan 26 06:45 ServerValidatingClient.exe
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:30.336 : Getting ServerValidatingClient.exe from server and saving as ServerValidatingClient.exe.copy
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:30.776 : Deleting ServerValidatingClient.exe
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:30.776 : Directory after delete:
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:31.137 :   no files
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:31.137 : Quitting client
    INFO [ServerValidatingClient] 26 Jan 2005 16:45:31.157 : Test complete

    There should now also be a file called YourFilename.copy in the local directory.

    If, instead of the above, something like the following output is produced:

    INFO [FullyValidatingClient] 25 Feb 2005 14:07:48.675 : Creating FTPS (explicit) client
    INFO [FullyValidatingClient] 25 Feb 2005 14:07:48.675 : Host-name checking enabled
    INFO [FullyValidatingClient] 25 Feb 2005 14:07:48.735 : Loading client cert from client.cert.pem and key from client.pvk with password password
    INFO [FullyValidatingClient] 25 Feb 2005 14:07:48.735 : Connecting to server localhost
    INFO [FullyValidatingClient] 25 Feb 2005 14:07:49.846 : Switching to FTPS (explicit mode)
    ERROR [FullyValidatingClient] 25 Feb 2005 14:07:49.906 : Caught exception Org.Mentalis.Security.Ssl.Shared.SslException The certificate could not be verified: NoCNMatch : 
    The certificate could not be verified: NoCNMatch
       at e.a(b2 A_0)
       at s.c()
       at EnterpriseDT.Net.Ftp.Pro.ProFTPClient.Auth(SecurityMechanism securityMechanism, Boolean secureDataChannels)
       at EnterpriseDT.Net.Ftp.Pro.ProFTPClient.Auth(SecurityMechanism securityMechanism)
       at FullyValidatingClient.Main(String[] args)

    then the name on the server's certificate does not match the actual server's host-name. In production environments this is a potentially serious issue (see Host-name Checking section below), but for the purposes of running this example, it is safe to disable host-name checking by running the example again with the hostname-checking command-line argument set to off.

Hostname Checking

Host-name checking is a simple check that is performed when a secure connection is being established. It involves comparing the following two items:

If they match then one can be confident that the server to which the client is connected is in fact the server to which the certificate was issued. If they do not match, then there's a possibility that the certificate has been stolen and that the server, to which the client is connected, is attempting to "impersonate" the actual server to which the client is actually connected. This is a form of "man-in-the-middle" attack, which gives the attacker complete control over the data being sent and received.

Unfortunately, the most widely compatible version of the X.509 certificate standard does not specify exactly how a host-name should be defined within a server certificate. The convention is that the Common Name (CN) field of the certificate should be used, and, while this is followed by the majority of Certificate Authorities (CAs), it is not universal.

If it is possible to configure the FTPS server's certificate then the Common Name (CN) field of the certificate must be the same as the host-name of the machine on which the FTPS server is running. If that server is an edtFTPD server then please refer to the following section for instructions on how to generate a suitable certificate.

Disabling host-name checking is strongly discouraged and should only be done as a last resort if the FTPS server's certificate cannot be configured so that its CN parameter contains its host-name.

For more information on keys, certificates, and Certification Authorities, please refer to the edtFTPnet/PRO Developer's Guide.

Generating Certificates for edtFTPD

Before generating a certificate for edtFTPD, please note that the server certificate that is distributed with edtFTPD has a Common Name (CN) parameter of localhost. This means that domain-name matching will be successful if the client and server are run on the same machine and the example is run with the hostname localhost or 127.0.0.1. If this is not the case, then a new certificate will be needed.

edtFTPD uses certificates of the PEM format also employed by OpenSSL. In order to generate certificates in the PEM format, you may use the OpenSSL toolkit. Information on obtaining binary forms of OpenSSL may be found here.

Once an OpenSSL executable has been obtained, the following command will generate a suitable server key and certificate:

> openssl genrsa -out server.key.pem 2048
> openssl req -new -x509 -key server.key.pem -out server.cert.pem -days 1095

The second command will prompt the user for a series of parameters. The only one that is important from edtFTPnet/PRO's point of view is the Common Name parameter. This parameter must be the same as the host-name of the server.

Once the server.key.pem and server.cert.pem have been generated they should be placed in the [edtFTPD directory]/etc directory.

Windows does not use the PEM format. OpenSSL may be used to convert the new server certificate in PEM format to PFX format. This may then be installed as per the instructions above.

		> openssl pkcs12 -export -in server.cert.pem -inkeyserver.key.pem -out certificate.pfx -name "My Certificate"