This example illustrates the use of ProFTPClient in explicit FTPS mode with server and client validation.
The example performs the following operations:
Note that the server's certificate is loaded manually as described below in (2).
You can view the source-code here.
Run the example by:
run remote-host username password filename client-cert-file client-key-file client-key-password (hostname-checking)
where
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.
Verify that the output looks something like this:
INFO [FullyValidatingClient] 25 Feb 2005 11:58:50.087 : Creating FTPS (explicit) client INFO [FullyValidatingClient] 25 Feb 2005 11:58:50.097 : Host-name checking enabled INFO [FullyValidatingClient] 25 Feb 2005 11:58:50.147 : Loading client cert from client.cert.pem and key from client.pvk with password password INFO [FullyValidatingClient] 25 Feb 2005 11:58:50.147 : Connecting to server edtmobile INFO [FullyValidatingClient] 25 Feb 2005 11:58:51.229 : Switching to FTPS (explicit mode) INFO [FullyValidatingClient] 25 Feb 2005 11:58:51.479 : Logging in with username=xxxxx INFO [FullyValidatingClient] 25 Feb 2005 11:58:51.499 : Setting up passive, ASCII transfers INFO [FullyValidatingClient] 25 Feb 2005 11:58:51.499 : Directory before put: INFO [FullyValidatingClient] 25 Feb 2005 11:58:51.649 : -rw-r--r-- 1 SYSTEM None 10014 Feb 4 10:02 readme.html INFO [FullyValidatingClient] 25 Feb 2005 11:58:51.649 : Putting FullyValidatingClient.cs to server INFO [FullyValidatingClient] 25 Feb 2005 11:58:51.860 : Directory after put: INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.000 : -rw-r--r-- 1 SYSTEM None 5390 Feb 25 11:58 FullyValidatingClient.cs INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.000 : -rw-r--r-- 1 SYSTEM None 10014 Feb 4 10:02 readme.html INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.000 : Getting FullyValidatingClient.cs from server and saving as FullyValidatingClient.cs.copy INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.200 : Deleting FullyValidatingClient.cs INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.200 : Directory after delete: INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.531 : -rw-r--r-- 1 SYSTEM None 10014 Feb 4 10:02 readme.html INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.531 : Quitting client INFO [FullyValidatingClient] 25 Feb 2005 11:58:52.531 : Test complete
There should now also be a file called FullyValidatingClient.cs.copy (the name of the transferred file in this case) 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.
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.
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.
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.
For more information on keys, certificates, and Certification Authorities, please refer to the edtFTPj/SSL Developer's Guide
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.
Like edtFTPj/SSL, 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 edtFTPj/SSL'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. The example may then be run again (don't forget to install the new server certificate on your machine).